diff --git a/system/osi/Android.bp b/system/osi/Android.bp
index 9a3bf1c916a56cb2752e923faf9b8fb3706d8077..25e594b3b26d7628a929580807e620b5afa65962 100644
--- a/system/osi/Android.bp
+++ b/system/osi/Android.bp
@@ -59,6 +59,12 @@ cc_library_static {
         "//packages/apps/Test/connectivity/sl4n",
         "//packages/modules/Bluetooth:__subpackages__",
     ],
+    export_include_dirs: [
+        "include",
+    ],
+    local_include_dirs: [
+        "include_internal",
+    ],
     defaults: ["fluoride_osi_defaults", "fluoride_basic_defaults"],
     // TODO(mcchou): Remove socket_utils sources after platform specific
     // dependencies are abstracted.
@@ -79,13 +85,15 @@ cc_library_static {
         "src/properties.cc",
         "src/reactor.cc",
         "src/ringbuffer.cc",
-        "src/semaphore.cc",
         "src/socket.cc",
         "src/socket_utils/socket_local_client.cc",
         "src/socket_utils/socket_local_server.cc",
         "src/thread.cc",
         "src/thread_scheduler.cc",
         "src/wakelock.cc",
+
+        // internal source that should not be used outside of libosi
+        "src/internal/semaphore.cc",
     ],
     host_supported: true,
     // TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
@@ -99,6 +107,9 @@ cc_library_static {
             ],
         },
     },
+    cflags: [
+        "-DLIB_OSI_INTERNAL",
+    ],
     min_sdk_version: "Tiramisu",
     apex_available: [
         "com.android.btservices",
@@ -130,9 +141,11 @@ cc_test {
         "test/rand_test.cc",
         "test/reactor_test.cc",
         "test/ringbuffer_test.cc",
-        "test/semaphore_test.cc",
         "test/thread_test.cc",
         "test/wakelock_test.cc",
+
+        // test internal sources only used inside the libosi
+        "test/internal/semaphore_test.cc",
     ],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
@@ -143,6 +156,10 @@ cc_test {
         "libcutils",
         "libcrypto",
     ],
+    local_include_dirs: [
+        "include_internal",
+        "test",
+    ],
     static_libs: [
         "libbt-common",
         "libbt-protos-lite",
@@ -155,6 +172,9 @@ cc_test {
             cflags: ["-DOS_GENERIC"],
         },
     },
+    cflags: [
+        "-DLIB_OSI_INTERNAL",
+    ],
     sanitize: {
         cfi: false,
     },
diff --git a/system/osi/BUILD.gn b/system/osi/BUILD.gn
index ceb30da4963d447c5b72859e0f1246fc3c08b30c..0f14260d658d1afee9afa3481e9fc92223b66cd8 100644
--- a/system/osi/BUILD.gn
+++ b/system/osi/BUILD.gn
@@ -32,7 +32,6 @@ static_library("osi") {
     "src/properties.cc",
     "src/reactor.cc",
     "src/ringbuffer.cc",
-    "src/semaphore.cc",
     "src/socket.cc",
 
     # TODO(mcchou): Remove these sources after platform specific
@@ -41,14 +40,22 @@ static_library("osi") {
     "src/socket_utils/socket_local_server.cc",
     "src/thread.cc",
     "src/wakelock.cc",
+
+    # internal dependencies to not be used outside
+    "src/internal/semaphore.cc",
   ]
 
   include_dirs = [
     "//bt/system/",
-    "//bt/system/linux_include",
     "//bt/system/internal_include",
-    "//bt/system/utils/include",
+    "//bt/system/linux_include",
+    "//bt/system/osi/include_internal",
     "//bt/system/stack/include",
+    "//bt/system/utils/include",
+  ]
+
+  cflags = [
+    "-DLIB_OSI_INTERNAL",
   ]
 
   deps = [
@@ -79,13 +86,20 @@ if (use.test) {
       "test/reactor_test.cc",
       "test/ringbuffer_test.cc",
       "test/thread_test.cc",
+
+      "test/internal/semaphore_test.cc",
     ]
 
     include_dirs = [
       "//bt/system/",
+      "//bt/system/osi/include_internal",
       "//bt/system/osi/test",
     ]
 
+    cflags = [
+      "-DLIB_OSI_INTERNAL",
+    ]
+
     deps = [
       "//bt/system/osi",
     ]
diff --git a/system/osi/include/semaphore.h b/system/osi/include_internal/osi/semaphore.h
similarity index 96%
rename from system/osi/include/semaphore.h
rename to system/osi/include_internal/osi/semaphore.h
index 3ae5e0fd63677f3af64eef81edcebe85442e8518..2fa3a9f49c9f355baf2c1d2179a52e5b37e9d5f0 100644
--- a/system/osi/include/semaphore.h
+++ b/system/osi/include_internal/osi/semaphore.h
@@ -18,6 +18,10 @@
 
 #pragma once
 
+#ifndef LIB_OSI_INTERNAL
+#error "Please do not include this outside of osi."
+#endif
+
 #include <stdbool.h>
 
 struct semaphore_t;
diff --git a/system/osi/src/alarm.cc b/system/osi/src/alarm.cc
index 19baacbd68226e4a0944663ba9787f19addf6736..2f0a27ea71c1fde6e9d638e3064f08874250b7f5 100644
--- a/system/osi/src/alarm.cc
+++ b/system/osi/src/alarm.cc
@@ -43,9 +43,9 @@
 #include "osi/include/list.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
-#include "osi/include/semaphore.h"
 #include "osi/include/thread.h"
 #include "osi/include/wakelock.h"
+#include "osi/semaphore.h"
 #include "stack/include/btu.h"
 
 using base::Bind;
diff --git a/system/osi/src/fixed_queue.cc b/system/osi/src/fixed_queue.cc
index b386fd9076360576e9797d8b99ef101027ee3cb5..f2fbf6a3263c8253e88450118e5228141ddda078 100644
--- a/system/osi/src/fixed_queue.cc
+++ b/system/osi/src/fixed_queue.cc
@@ -27,7 +27,7 @@
 #include "osi/include/list.h"
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
-#include "osi/include/semaphore.h"
+#include "osi/semaphore.h"
 
 typedef struct fixed_queue_t {
   list_t* list;
diff --git a/system/osi/src/future.cc b/system/osi/src/future.cc
index 878b5ad6b4931371a3d2a6a97ba2bc73d58f50f5..fe97b9c393f8346229992bd80d9feec79fb7a724 100644
--- a/system/osi/src/future.cc
+++ b/system/osi/src/future.cc
@@ -26,7 +26,7 @@
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
-#include "osi/include/semaphore.h"
+#include "osi/semaphore.h"
 
 struct future_t {
   bool ready_can_be_called;
diff --git a/system/osi/src/semaphore.cc b/system/osi/src/internal/semaphore.cc
similarity index 98%
rename from system/osi/src/semaphore.cc
rename to system/osi/src/internal/semaphore.cc
index f209d728905039028a2559406d1b3727bc29217e..fb95e2b14a5c6e413df0750e4c9ed5635875691a 100644
--- a/system/osi/src/semaphore.cc
+++ b/system/osi/src/internal/semaphore.cc
@@ -18,7 +18,7 @@
 
 #define LOG_TAG "bt_osi_semaphore"
 
-#include "osi/include/semaphore.h"
+#include "osi/semaphore.h"
 
 #include <base/logging.h>
 #include <errno.h>
diff --git a/system/osi/src/thread.cc b/system/osi/src/thread.cc
index a8ac5ad7bb1315fa65f2a373ad825751bc7ed770..d4528c96d95b3e9798fd89f3210e30d929e04988 100644
--- a/system/osi/src/thread.cc
+++ b/system/osi/src/thread.cc
@@ -38,7 +38,7 @@
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
 #include "osi/include/reactor.h"
-#include "osi/include/semaphore.h"
+#include "osi/semaphore.h"
 
 struct thread_t {
   std::atomic_bool is_joined{false};
diff --git a/system/osi/test/alarm_test.cc b/system/osi/test/alarm_test.cc
index 7c30bf353e188521f250092db26ae1682c8303d6..7b42bbc9fe963282cee6ea3faa01ef2932c4901c 100644
--- a/system/osi/test/alarm_test.cc
+++ b/system/osi/test/alarm_test.cc
@@ -25,7 +25,7 @@
 #include "osi/include/alarm.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/osi.h"
-#include "osi/include/semaphore.h"
+#include "osi/semaphore.h"
 
 using base::Closure;
 using base::TimeDelta;
diff --git a/system/osi/test/fuzzers/alarm/fuzz_alarm.cc b/system/osi/test/fuzzers/alarm/fuzz_alarm.cc
index c432f8c5c1d80bce6e82fb8c7cd9d3a4e25b69ed..126078ded39b30a1d94b5c6566d089bd8ea4f633 100644
--- a/system/osi/test/fuzzers/alarm/fuzz_alarm.cc
+++ b/system/osi/test/fuzzers/alarm/fuzz_alarm.cc
@@ -17,7 +17,6 @@
 #include <fcntl.h>
 #include <fuzzer/FuzzedDataProvider.h>
 #include "osi/include/alarm.h"
-#include "osi/include/semaphore.h"
 
 #include "common/message_loop_thread.h"
 
@@ -29,7 +28,37 @@ using bluetooth::common::MessageLoopThread;
 #define MAX_BUFFER_LEN 4096
 #define MAX_ALARM_DURATION 25
 
-static semaphore_t* semaphore;
+class btsemaphore {
+ public:
+  void post() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    ++mCount;
+    mCondition.notify_one();
+  }
+
+  void wait() {
+    std::unique_lock<std::mutex> lock(mMutex);
+    while (!mCount) {
+      mCondition.wait(lock);
+    }
+    --mCount;
+  }
+
+  bool try_wait() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mCount) {
+      --mCount;
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  std::mutex mMutex;
+  std::condition_variable mCondition;
+  unsigned long mCount = 0;
+};
+static btsemaphore semaphore;
 static int cb_counter;
 static MessageLoopThread* thread = new MessageLoopThread("fake main thread");
 
@@ -37,14 +66,13 @@ bluetooth::common::MessageLoopThread* get_main_thread() { return thread; }
 
 static void cb(void* data) {
   ++cb_counter;
-  semaphore_post(semaphore);
+  semaphore.post();
 }
 
 void setup() {
   cb_counter = 0;
-  semaphore = semaphore_new(0);
 }
-void teardown() { semaphore_free(semaphore); }
+void teardown() { }
 
 alarm_t* fuzz_init_alarm(FuzzedDataProvider* dataProvider) {
   size_t name_len =
@@ -130,7 +158,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
 
     // Wait for them to complete
     for (int i = 1; i <= num_alarms; i++) {
-      semaphore_wait(semaphore);
+      semaphore.wait();
     }
   }
 
diff --git a/system/osi/test/semaphore_test.cc b/system/osi/test/internal/semaphore_test.cc
similarity index 98%
rename from system/osi/test/semaphore_test.cc
rename to system/osi/test/internal/semaphore_test.cc
index 54046a85159f118ec33726024ba066589c0f879d..41851811d2ddd4c3ca8d0815c8c1ca62f53f9cbe 100644
--- a/system/osi/test/semaphore_test.cc
+++ b/system/osi/test/internal/semaphore_test.cc
@@ -9,7 +9,7 @@
 #include "common/message_loop_thread.h"
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
-#include "osi/include/semaphore.h"
+#include "osi/semaphore.h"
 
 using bluetooth::common::MessageLoopThread;
 
diff --git a/system/test/mock/mock_osi_alarm.h b/system/test/mock/mock_osi_alarm.h
index 18c15aec9aa9abc3331838013013ef21e11d32f1..88ae09e5a9f542fd164046e2430ea69471a27918 100644
--- a/system/test/mock/mock_osi_alarm.h
+++ b/system/test/mock/mock_osi_alarm.h
@@ -56,7 +56,6 @@ extern std::map<std::string, int> mock_function_count_map;
 #include "osi/include/list.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
-#include "osi/include/semaphore.h"
 #include "osi/include/thread.h"
 #include "osi/include/wakelock.h"
 
diff --git a/system/test/mock/mock_osi_fixed_queue.h b/system/test/mock/mock_osi_fixed_queue.h
index 0534ef8b9691d229ef6ac2a0a2e080548f5ea76a..e14b4a3fc434b78898616f80a3e2960a4fff4a73 100644
--- a/system/test/mock/mock_osi_fixed_queue.h
+++ b/system/test/mock/mock_osi_fixed_queue.h
@@ -45,7 +45,6 @@ extern std::map<std::string, int> mock_function_count_map;
 #include "osi/include/list.h"
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
-#include "osi/include/semaphore.h"
 
 // Mocked compile conditionals, if any
 
diff --git a/system/test/mock/mock_osi_future.h b/system/test/mock/mock_osi_future.h
index 7d95b85bfe161f1abcc7545d921639bca485ad3f..c77460a2f3cf7d5ca34f1c29133c7a77aecb42fc 100644
--- a/system/test/mock/mock_osi_future.h
+++ b/system/test/mock/mock_osi_future.h
@@ -41,7 +41,6 @@ extern std::map<std::string, int> mock_function_count_map;
 #include "osi/include/future.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
-#include "osi/include/semaphore.h"
 
 // Mocked compile conditionals, if any
 
diff --git a/system/test/mock/mock_osi_semaphore.cc b/system/test/mock/mock_osi_semaphore.cc
deleted file mode 100644
index 4a69c0e16e6f10b7fd4ad6bd1c048f000e88703e..0000000000000000000000000000000000000000
--- a/system/test/mock/mock_osi_semaphore.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- *   Functions generated:6
- *
- *  mockcify.pl ver 0.3.0
- */
-
-#include <cstdint>
-#include <functional>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-// Mock include file to share data between tests and mock
-#include "test/mock/mock_osi_semaphore.h"
-
-// Mocked internal structures, if any
-
-namespace test {
-namespace mock {
-namespace osi_semaphore {
-
-// Function state capture and return values, if needed
-struct semaphore_free semaphore_free;
-struct semaphore_get_fd semaphore_get_fd;
-struct semaphore_new semaphore_new;
-struct semaphore_post semaphore_post;
-struct semaphore_try_wait semaphore_try_wait;
-struct semaphore_wait semaphore_wait;
-
-}  // namespace osi_semaphore
-}  // namespace mock
-}  // namespace test
-
-// Mocked functions, if any
-void semaphore_free(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  test::mock::osi_semaphore::semaphore_free(semaphore);
-}
-int semaphore_get_fd(const semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  return test::mock::osi_semaphore::semaphore_get_fd(semaphore);
-}
-semaphore_t* semaphore_new(unsigned int value) {
-  mock_function_count_map[__func__]++;
-  return test::mock::osi_semaphore::semaphore_new(value);
-}
-void semaphore_post(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  test::mock::osi_semaphore::semaphore_post(semaphore);
-}
-bool semaphore_try_wait(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  return test::mock::osi_semaphore::semaphore_try_wait(semaphore);
-}
-void semaphore_wait(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  test::mock::osi_semaphore::semaphore_wait(semaphore);
-}
-// Mocked functions complete
-// END mockcify generation
diff --git a/system/test/mock/mock_osi_semaphore.h b/system/test/mock/mock_osi_semaphore.h
deleted file mode 100644
index ca862ea03bb76dd0e603cfa62982ba6b7d9270f7..0000000000000000000000000000000000000000
--- a/system/test/mock/mock_osi_semaphore.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- *   Functions generated:6
- *
- *  mockcify.pl ver 0.3.0
- */
-
-#include <cstdint>
-#include <functional>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-// Original included files, if any
-// NOTE: Since this is a mock file with mock definitions some number of
-//       include files may not be required.  The include-what-you-use
-//       still applies, but crafting proper inclusion is out of scope
-//       for this effort.  This compilation unit may compile as-is, or
-//       may need attention to prune from (or add to ) the inclusion set.
-#include <base/logging.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <string.h>
-#include <sys/eventfd.h>
-#include <unistd.h>
-
-#include "check.h"
-#include "osi/include/allocator.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "osi/include/semaphore.h"
-
-// Mocked compile conditionals, if any
-
-namespace test {
-namespace mock {
-namespace osi_semaphore {
-
-// Shared state between mocked functions and tests
-// Name: semaphore_free
-// Params: semaphore_t* semaphore
-// Return: void
-struct semaphore_free {
-  std::function<void(semaphore_t* semaphore)> body{
-      [](semaphore_t* semaphore) {}};
-  void operator()(semaphore_t* semaphore) { body(semaphore); };
-};
-extern struct semaphore_free semaphore_free;
-
-// Name: semaphore_get_fd
-// Params: const semaphore_t* semaphore
-// Return: int
-struct semaphore_get_fd {
-  int return_value{0};
-  std::function<int(const semaphore_t* semaphore)> body{
-      [this](const semaphore_t* semaphore) { return return_value; }};
-  int operator()(const semaphore_t* semaphore) { return body(semaphore); };
-};
-extern struct semaphore_get_fd semaphore_get_fd;
-
-// Name: semaphore_new
-// Params: unsigned int value
-// Return: semaphore_t*
-struct semaphore_new {
-  semaphore_t* return_value{0};
-  std::function<semaphore_t*(unsigned int value)> body{
-      [this](unsigned int value) { return return_value; }};
-  semaphore_t* operator()(unsigned int value) { return body(value); };
-};
-extern struct semaphore_new semaphore_new;
-
-// Name: semaphore_post
-// Params: semaphore_t* semaphore
-// Return: void
-struct semaphore_post {
-  std::function<void(semaphore_t* semaphore)> body{
-      [](semaphore_t* semaphore) {}};
-  void operator()(semaphore_t* semaphore) { body(semaphore); };
-};
-extern struct semaphore_post semaphore_post;
-
-// Name: semaphore_try_wait
-// Params: semaphore_t* semaphore
-// Return: bool
-struct semaphore_try_wait {
-  bool return_value{false};
-  std::function<bool(semaphore_t* semaphore)> body{
-      [this](semaphore_t* semaphore) { return return_value; }};
-  bool operator()(semaphore_t* semaphore) { return body(semaphore); };
-};
-extern struct semaphore_try_wait semaphore_try_wait;
-
-// Name: semaphore_wait
-// Params: semaphore_t* semaphore
-// Return: void
-struct semaphore_wait {
-  std::function<void(semaphore_t* semaphore)> body{
-      [](semaphore_t* semaphore) {}};
-  void operator()(semaphore_t* semaphore) { body(semaphore); };
-};
-extern struct semaphore_wait semaphore_wait;
-
-}  // namespace osi_semaphore
-}  // namespace mock
-}  // namespace test
-
-// END mockcify generation
\ No newline at end of file
diff --git a/system/test/mock/mock_osi_thread.h b/system/test/mock/mock_osi_thread.h
index 7bcab0849f10e5a006884fcc6675dd1e93616fce..042b3a686c48649ee54abc664e833272ab74e016 100644
--- a/system/test/mock/mock_osi_thread.h
+++ b/system/test/mock/mock_osi_thread.h
@@ -52,7 +52,6 @@ extern std::map<std::string, int> mock_function_count_map;
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
 #include "osi/include/reactor.h"
-#include "osi/include/semaphore.h"
 #include "osi/include/thread.h"
 
 // Mocked compile conditionals, if any
diff --git a/system/test/stub/osi.cc b/system/test/stub/osi.cc
index 6c879471c2f1e35d62a22bdc00d7d33b7c44cc1e..844e7576d2a83b1f39f3ea8f4f292137182f955c 100644
--- a/system/test/stub/osi.cc
+++ b/system/test/stub/osi.cc
@@ -41,7 +41,6 @@ extern std::map<std::string, int> mock_function_count_map;
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
 #include "osi/include/ringbuffer.h"
-#include "osi/include/semaphore.h"
 #include "osi/include/socket.h"
 #include "osi/include/thread.h"
 #include "osi/include/wakelock.h"
@@ -626,28 +625,6 @@ int32_t osi_property_get_int32(const char* key, int32_t default_value) {
   return 0;
 }
 
-bool semaphore_try_wait(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  return false;
-}
-int semaphore_get_fd(const semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-  return 0;
-}
-semaphore_t* semaphore_new(unsigned int value) {
-  mock_function_count_map[__func__]++;
-  return nullptr;
-}
-void semaphore_free(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-}
-void semaphore_post(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-}
-void semaphore_wait(semaphore_t* semaphore) {
-  mock_function_count_map[__func__]++;
-}
-
 bool wakelock_acquire(void) {
   mock_function_count_map[__func__]++;
   return false;
diff --git a/system/test/suite/adapter/bluetooth_test.cc b/system/test/suite/adapter/bluetooth_test.cc
index 6b24b7509c801df75c58b436af90995092fb1d34..79ce2a31f23fc28f6bb7130d5ac508fc0a048344 100644
--- a/system/test/suite/adapter/bluetooth_test.cc
+++ b/system/test/suite/adapter/bluetooth_test.cc
@@ -34,6 +34,16 @@ std::mutex callback_lock;
 
 }  // namespace
 
+void semaphore_wait(btsemaphore &s) {
+  s.wait();
+}
+void semaphore_post(btsemaphore &s) {
+  s.post();
+}
+void semaphore_try_wait(btsemaphore &s) {
+  s.try_wait();
+}
+
 namespace bttest {
 
 void BluetoothTest::SetUp() {
@@ -53,10 +63,6 @@ void BluetoothTest::SetUp() {
 
   bluetooth::hal::BluetoothInterface::Initialize();
   ASSERT_TRUE(bluetooth::hal::BluetoothInterface::IsInitialized());
-  adapter_properties_callback_sem_ = semaphore_new(0);
-  remote_device_properties_callback_sem_ = semaphore_new(0);
-  adapter_state_changed_callback_sem_ = semaphore_new(0);
-  discovery_state_changed_callback_sem_ = semaphore_new(0);
 
   auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
   bt_hal_interface->AddObserver(this);
@@ -65,10 +71,6 @@ void BluetoothTest::SetUp() {
 }
 
 void BluetoothTest::TearDown() {
-  semaphore_free(adapter_properties_callback_sem_);
-  semaphore_free(remote_device_properties_callback_sem_);
-  semaphore_free(adapter_state_changed_callback_sem_);
-  semaphore_free(discovery_state_changed_callback_sem_);
 
   auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
   bt_hal_interface->RemoveObserver(this);
@@ -76,8 +78,8 @@ void BluetoothTest::TearDown() {
   ASSERT_FALSE(bt_hal_interface->IsInitialized());
 }
 
-void BluetoothTest::ClearSemaphore(semaphore_t* sem) {
-  while (semaphore_try_wait(sem))
+void BluetoothTest::ClearSemaphore(btsemaphore& sem) {
+  while (sem.try_wait())
     ;
 }
 
diff --git a/system/test/suite/adapter/bluetooth_test.h b/system/test/suite/adapter/bluetooth_test.h
index 6b50be9f95d04fc8d79b9d22de5f0ed06edbfdee..d1946bd0e9b37dcd3e35a98c2a0e652643c6a2a3 100644
--- a/system/test/suite/adapter/bluetooth_test.h
+++ b/system/test/suite/adapter/bluetooth_test.h
@@ -29,10 +29,46 @@
 #include <map>
 #include <string>
 
-#include "osi/include/semaphore.h"
 #include "service/hal/bluetooth_interface.h"
 #include "types/raw_address.h"
 
+#include <mutex>
+#include <condition_variable>
+
+class btsemaphore {
+ public:
+  void post() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    ++mCount;
+    mCondition.notify_one();
+  }
+
+  void wait() {
+    std::unique_lock<std::mutex> lock(mMutex);
+    while (!mCount) {
+      mCondition.wait(lock);
+    }
+    --mCount;
+  }
+
+  bool try_wait() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mCount) {
+      --mCount;
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  std::mutex mMutex;
+  std::condition_variable mCondition;
+  unsigned long mCount = 0;
+};
+void semaphore_wait(btsemaphore &s);
+void semaphore_post(btsemaphore &s);
+void semaphore_try_wait(btsemaphore &s);
+
 namespace bttest {
 
 // This class represents the Bluetooth testing framework and provides
@@ -73,7 +109,7 @@ class BluetoothTest : public ::testing::Test,
   bt_bond_state_t GetBondState();
 
   // Reset a semaphores count to 0
-  void ClearSemaphore(semaphore_t* sem);
+  void ClearSemaphore(btsemaphore& sem);
 
   // SetUp initializes the Bluetooth interface and registers the callbacks
   // before running every test
@@ -100,10 +136,10 @@ class BluetoothTest : public ::testing::Test,
 
   // Semaphores used to wait for specific callback execution. Each callback
   // has its own semaphore associated with it.
-  semaphore_t* adapter_properties_callback_sem_;
-  semaphore_t* remote_device_properties_callback_sem_;
-  semaphore_t* adapter_state_changed_callback_sem_;
-  semaphore_t* discovery_state_changed_callback_sem_;
+  btsemaphore adapter_properties_callback_sem_;
+  btsemaphore remote_device_properties_callback_sem_;
+  btsemaphore adapter_state_changed_callback_sem_;
+  btsemaphore discovery_state_changed_callback_sem_;
 
  private:
   // The bluetooth interface that all the tests use to interact with the HAL
diff --git a/system/test/suite/gatt/gatt_test.cc b/system/test/suite/gatt/gatt_test.cc
index ef0e5d62e2600b14750f6cf2bf3e54a9f85cce12..68cb2f77af982ff8ff208eb27b8634f650578cf3 100644
--- a/system/test/suite/gatt/gatt_test.cc
+++ b/system/test/suite/gatt/gatt_test.cc
@@ -40,14 +40,6 @@ void GattTest::SetUp() {
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_TRUE(GetState() == BT_STATE_ON);
 
-  register_client_callback_sem_ = semaphore_new(0);
-  scan_result_callback_sem_ = semaphore_new(0);
-
-  register_server_callback_sem_ = semaphore_new(0);
-  service_added_callback_sem_ = semaphore_new(0);
-  service_stopped_callback_sem_ = semaphore_new(0);
-  service_deleted_callback_sem_ = semaphore_new(0);
-
   bluetooth::hal::BluetoothGattInterface::Initialize();
   ASSERT_TRUE(bluetooth::hal::BluetoothGattInterface::IsInitialized());
   auto gatt_interface = bluetooth::hal::BluetoothGattInterface::Get();
@@ -65,14 +57,6 @@ void GattTest::TearDown() {
   gatt_client_interface_ = nullptr;
   gatt_server_interface_ = nullptr;
 
-  semaphore_free(register_client_callback_sem_);
-  semaphore_free(scan_result_callback_sem_);
-
-  semaphore_free(register_server_callback_sem_);
-  semaphore_free(service_added_callback_sem_);
-  semaphore_free(service_stopped_callback_sem_);
-  semaphore_free(service_deleted_callback_sem_);
-
   bluetooth::hal::BluetoothGattInterface::CleanUp();
 
   ASSERT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
diff --git a/system/test/suite/gatt/gatt_test.h b/system/test/suite/gatt/gatt_test.h
index da0d6d218c3b7ced4124218397b74fc3c7929905..2704030c9a824924eca2cd4cebcd9957a3fa36a6 100644
--- a/system/test/suite/gatt/gatt_test.h
+++ b/system/test/suite/gatt/gatt_test.h
@@ -85,17 +85,17 @@ class GattTest : public BluetoothTest,
 
   // Semaphores used to wait for specific callback execution. Each callback
   // has its own semaphore associated with it
-  semaphore_t* register_client_callback_sem_;
-  semaphore_t* scan_result_callback_sem_;
-  semaphore_t* listen_callback_sem_;
-
-  semaphore_t* register_server_callback_sem_;
-  semaphore_t* service_added_callback_sem_;
-  semaphore_t* characteristic_added_callback_sem_;
-  semaphore_t* descriptor_added_callback_sem_;
-  semaphore_t* service_started_callback_sem_;
-  semaphore_t* service_stopped_callback_sem_;
-  semaphore_t* service_deleted_callback_sem_;
+  btsemaphore register_client_callback_sem_;
+  btsemaphore scan_result_callback_sem_;
+  btsemaphore listen_callback_sem_;
+
+  btsemaphore register_server_callback_sem_;
+  btsemaphore service_added_callback_sem_;
+  btsemaphore characteristic_added_callback_sem_;
+  btsemaphore descriptor_added_callback_sem_;
+  btsemaphore service_started_callback_sem_;
+  btsemaphore service_stopped_callback_sem_;
+  btsemaphore service_deleted_callback_sem_;
 
  private:
   // The btgatt_scanner_interface_t that all the tests use to interact with the