diff --git a/system/btcore/src/hal_util.cc b/system/btcore/src/hal_util.cc
index 616bd2b46f46f705ae491393a4c94db01790170c..ab1a3b40690071ab793fe6d162b234afba74a7b1 100644
--- a/system/btcore/src/hal_util.cc
+++ b/system/btcore/src/hal_util.cc
@@ -29,44 +29,6 @@
 
 using base::StringPrintf;
 
-#define BLUETOOTH_LIBRARY_NAME "libbluetooth.so"
-
-#if !defined(STATIC_LIBBLUETOOTH)
-int hal_util_load_bt_library(const bt_interface_t** interface) {
-  const char* sym = BLUETOOTH_INTERFACE_STRING;
-  bt_interface_t* itf = nullptr;
-
-  // Always try to load the default Bluetooth stack on GN builds.
-  void* handle = dlopen(BLUETOOTH_LIBRARY_NAME, RTLD_NOW);
-  if (!handle) {
-    const char* err_str = dlerror();
-    LOG(ERROR) << __func__ << ": failed to load bluetooth library, error="
-               << (err_str ? err_str : "error unknown");
-    goto error;
-  }
-
-  // Get the address of the bt_interface_t.
-  itf = (bt_interface_t*)dlsym(handle, sym);
-  if (!itf) {
-    LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library "
-               << sym;
-    goto error;
-  }
-
-  // Success.
-  LOG(INFO) << __func__ << " loaded HAL path=" << BLUETOOTH_LIBRARY_NAME
-            << " btinterface=" << itf << " handle=" << handle;
-
-  *interface = itf;
-  return 0;
-
-error:
-  *interface = NULL;
-  if (handle) dlclose(handle);
-
-  return -EINVAL;
-}
-#else
 extern bt_interface_t bluetoothInterface;
 
 int hal_util_load_bt_library(const bt_interface_t** interface) {
@@ -74,4 +36,3 @@ int hal_util_load_bt_library(const bt_interface_t** interface) {
 
   return 0;
 }
-#endif
diff --git a/system/btif/test/btif_core_test.cc b/system/btif/test/btif_core_test.cc
index 8f833516145244df992918b59a36ffafdb970a79..4512827e51ee8400c2342952c32826a62cb1b37e 100644
--- a/system/btif/test/btif_core_test.cc
+++ b/system/btif/test/btif_core_test.cc
@@ -20,6 +20,7 @@
 #include <map>
 
 #include "bta/include/bta_ag_api.h"
+#include "btcore/include/module.h"
 #include "btif/include/btif_api.h"
 #include "btif/include/btif_common.h"
 #include "types/raw_address.h"
@@ -32,6 +33,12 @@ uint8_t btu_trace_level = BT_TRACE_LEVEL_DEBUG;
 
 const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {};
 
+module_t bt_utils_module;
+module_t gd_controller_module;
+module_t gd_idle_module;
+module_t gd_shim_module;
+module_t osi_module;
+
 namespace {
 
 auto timeout_time = std::chrono::seconds(3);
diff --git a/system/service/bluetooth_interface.cc b/system/service/bluetooth_interface.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ee58ef3103957413559d2f68391c5ad70b49d4ab
--- /dev/null
+++ b/system/service/bluetooth_interface.cc
@@ -0,0 +1,874 @@
+/******************************************************************************
+ *
+ *  Copyright 2009-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      bluetooth.c
+ *
+ *  Description:   Bluetooth HAL implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif"
+
+#include <base/logging.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bluetooth_headset_interface.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_csis.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_hd.h>
+#include <hardware/bt_hearing_aid.h>
+#include <hardware/bt_hf_client.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_le_audio.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_rc.h>
+#include <hardware/bt_sdp.h>
+#include <hardware/bt_sock.h>
+#include <hardware/bt_vc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bta/include/bta_csis_api.h"
+#include "bta/include/bta_hearing_aid_api.h"
+#include "bta/include/bta_hf_client_api.h"
+#include "bta/include/bta_le_audio_api.h"
+#include "btif/avrcp/avrcp_service.h"
+#include "btif/include/stack_manager.h"
+#include "btif_a2dp.h"
+#include "btif_activity_attribution.h"
+#include "btif_api.h"
+#include "btif_av.h"
+#include "btif_bqr.h"
+#include "btif_config.h"
+#include "btif_debug.h"
+#include "btif_debug_btsnoop.h"
+#include "btif_debug_conn.h"
+#include "btif_hf.h"
+#include "btif_keystore.h"
+#include "btif_metrics_logging.h"
+#include "btif_storage.h"
+#include "common/address_obfuscator.h"
+#include "common/metric_id_allocator.h"
+#include "common/metrics.h"
+#include "common/os_utils.h"
+#include "device/include/interop.h"
+#include "gd/common/init_flags.h"
+#include "main/shim/dumpsys.h"
+#include "main/shim/shim.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocation_tracker.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/wakelock.h"
+#include "stack/gatt/connection_manager.h"
+#include "stack/include/avdt_api.h"
+#include "stack/include/btm_api.h"
+#include "stack/include/btu.h"
+#include "types/raw_address.h"
+
+using bluetooth::csis::CsisClientInterface;
+using bluetooth::hearing_aid::HearingAidInterface;
+using bluetooth::le_audio::LeAudioClientInterface;
+using bluetooth::vc::VolumeControlInterface;
+
+/*******************************************************************************
+ *  Static variables
+ ******************************************************************************/
+
+static bt_callbacks_t* bt_hal_cbacks = NULL;
+bool restricted_mode = false;
+bool common_criteria_mode = false;
+const int CONFIG_COMPARE_ALL_PASS = 0b11;
+int common_criteria_config_compare_result = CONFIG_COMPARE_ALL_PASS;
+bool is_local_device_atv = false;
+
+/*******************************************************************************
+ *  Externs
+ ******************************************************************************/
+
+/* list all extended interfaces here */
+
+/* handsfree profile - client */
+extern const bthf_client_interface_t* btif_hf_client_get_interface();
+/* advanced audio profile */
+extern const btav_source_interface_t* btif_av_get_src_interface();
+extern const btav_sink_interface_t* btif_av_get_sink_interface();
+/*rfc l2cap*/
+extern const btsock_interface_t* btif_sock_get_interface();
+/* hid host profile */
+extern const bthh_interface_t* btif_hh_get_interface();
+/* hid device profile */
+extern const bthd_interface_t* btif_hd_get_interface();
+/*pan*/
+extern const btpan_interface_t* btif_pan_get_interface();
+/* gatt */
+extern const btgatt_interface_t* btif_gatt_get_interface();
+/* avrc target */
+extern const btrc_interface_t* btif_rc_get_interface();
+/* avrc controller */
+extern const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface();
+/*SDP search client*/
+extern const btsdp_interface_t* btif_sdp_get_interface();
+/*Hearing Aid client*/
+extern HearingAidInterface* btif_hearing_aid_get_interface();
+/* LeAudio testi client */
+extern LeAudioClientInterface* btif_le_audio_get_interface();
+/* Coordinated Set Service Client */
+extern CsisClientInterface* btif_csis_client_get_interface();
+/* Volume Control client */
+extern VolumeControlInterface* btif_volume_control_get_interface();
+
+/*******************************************************************************
+ *  Functions
+ ******************************************************************************/
+
+static bool interface_ready(void) { return bt_hal_cbacks != NULL; }
+void set_hal_cbacks(bt_callbacks_t* callbacks) { bt_hal_cbacks = callbacks; }
+
+static bool is_profile(const char* p1, const char* p2) {
+  CHECK(p1);
+  CHECK(p2);
+  return strlen(p1) == strlen(p2) && strncmp(p1, p2, strlen(p2)) == 0;
+}
+
+/*****************************************************************************
+ *
+ *   BLUETOOTH HAL INTERFACE FUNCTIONS
+ *
+ ****************************************************************************/
+
+static int init(bt_callbacks_t* callbacks, bool start_restricted,
+                bool is_common_criteria_mode, int config_compare_result,
+                const char** init_flags, bool is_atv) {
+  LOG_INFO(
+      "%s: start restricted = %d ; common criteria mode = %d, config compare "
+      "result = %d",
+      __func__, start_restricted, is_common_criteria_mode,
+      config_compare_result);
+
+  bluetooth::common::InitFlags::Load(init_flags);
+
+  if (interface_ready()) return BT_STATUS_DONE;
+
+#ifdef BLUEDROID_DEBUG
+  allocation_tracker_init();
+#endif
+
+  set_hal_cbacks(callbacks);
+
+  restricted_mode = start_restricted;
+  common_criteria_mode = is_common_criteria_mode;
+  common_criteria_config_compare_result = config_compare_result;
+  is_local_device_atv = is_atv;
+
+  stack_manager_get_interface()->init_stack();
+  btif_debug_init();
+  return BT_STATUS_SUCCESS;
+}
+
+static int enable() {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  stack_manager_get_interface()->start_up_stack_async();
+  return BT_STATUS_SUCCESS;
+}
+
+static int disable(void) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  stack_manager_get_interface()->shut_down_stack_async();
+  return BT_STATUS_SUCCESS;
+}
+
+static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); }
+
+bool is_restricted_mode() { return restricted_mode; }
+bool is_common_criteria_mode() {
+  return is_bluetooth_uid() && common_criteria_mode;
+}
+// if common criteria mode disable, will always return
+// CONFIG_COMPARE_ALL_PASS(0b11) indicate don't check config checksum.
+int get_common_criteria_config_compare_result() {
+  return is_common_criteria_mode() ? common_criteria_config_compare_result
+                                   : CONFIG_COMPARE_ALL_PASS;
+}
+
+bool is_atv_device() { return is_local_device_atv; }
+
+static int get_adapter_properties(void) {
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_get_adapter_properties));
+  return BT_STATUS_SUCCESS;
+}
+
+static int get_adapter_property(bt_property_type_t type) {
+  /* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */
+  if (!btif_is_enabled() && (type != BT_PROPERTY_BDADDR) &&
+      (type != BT_PROPERTY_BDNAME) && (type != BT_PROPERTY_CLASS_OF_DEVICE))
+    return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_get_adapter_property, type));
+  return BT_STATUS_SUCCESS;
+}
+
+static int set_adapter_property(const bt_property_t* property) {
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  switch (property->type) {
+    case BT_PROPERTY_BDNAME:
+    case BT_PROPERTY_ADAPTER_SCAN_MODE:
+    case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+    case BT_PROPERTY_CLASS_OF_DEVICE:
+    case BT_PROPERTY_LOCAL_IO_CAPS:
+    case BT_PROPERTY_LOCAL_IO_CAPS_BLE:
+      break;
+    default:
+      return BT_STATUS_FAIL;
+  }
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(
+                                   [](bt_property_t* property) {
+                                     btif_set_adapter_property(property);
+                                     osi_free(property);
+                                   },
+                                   property_deep_copy(property)));
+  return BT_STATUS_SUCCESS;
+}
+
+int get_remote_device_properties(RawAddress* remote_addr) {
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_get_remote_device_properties,
+                                              *remote_addr));
+  return BT_STATUS_SUCCESS;
+}
+
+int get_remote_device_property(RawAddress* remote_addr,
+                               bt_property_type_t type) {
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_get_remote_device_property,
+                                              *remote_addr, type));
+  return BT_STATUS_SUCCESS;
+}
+
+int set_remote_device_property(RawAddress* remote_addr,
+                               const bt_property_t* property) {
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(
+      FROM_HERE, base::BindOnce(
+                     [](RawAddress remote_addr, bt_property_t* property) {
+                       btif_set_remote_device_property(&remote_addr, property);
+                       osi_free(property);
+                     },
+                     *remote_addr, property_deep_copy(property)));
+  return BT_STATUS_SUCCESS;
+}
+
+int get_remote_services(RawAddress* remote_addr, int transport) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_get_remote_services,
+                                              *remote_addr, transport));
+  return BT_STATUS_SUCCESS;
+}
+
+static int start_discovery(void) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_start_discovery));
+  return BT_STATUS_SUCCESS;
+}
+
+static int cancel_discovery(void) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_cancel_discovery));
+  return BT_STATUS_SUCCESS;
+}
+
+static int create_bond(const RawAddress* bd_addr, int transport) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+  if (btif_dm_pairing_is_busy()) return BT_STATUS_BUSY;
+
+  do_in_main_thread(FROM_HERE,
+                    base::BindOnce(btif_dm_create_bond, *bd_addr, transport));
+  return BT_STATUS_SUCCESS;
+}
+
+static int create_bond_out_of_band(const RawAddress* bd_addr, int transport,
+                                   const bt_oob_data_t* p192_data,
+                                   const bt_oob_data_t* p256_data) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+  if (btif_dm_pairing_is_busy()) return BT_STATUS_BUSY;
+
+  do_in_main_thread(FROM_HERE,
+                    base::BindOnce(btif_dm_create_bond_out_of_band, *bd_addr,
+                                   transport, *p192_data, *p256_data));
+  return BT_STATUS_SUCCESS;
+}
+
+static int generate_local_oob_data(tBT_TRANSPORT transport) {
+  LOG_INFO("%s", __func__);
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  return do_in_main_thread(
+      FROM_HERE, base::BindOnce(btif_dm_generate_local_oob_data, transport));
+}
+
+static int cancel_bond(const RawAddress* bd_addr) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_cancel_bond, *bd_addr));
+  return BT_STATUS_SUCCESS;
+}
+
+static int remove_bond(const RawAddress* bd_addr) {
+  if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr))
+    return BT_STATUS_SUCCESS;
+
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_remove_bond, *bd_addr));
+  return BT_STATUS_SUCCESS;
+}
+
+static int get_connection_state(const RawAddress* bd_addr) {
+  if (!interface_ready()) return 0;
+
+  return btif_dm_get_connection_state(bd_addr);
+}
+
+static int pin_reply(const RawAddress* bd_addr, uint8_t accept, uint8_t pin_len,
+                     bt_pin_code_t* pin_code) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+  if (pin_code == nullptr || pin_len > PIN_CODE_LEN) return BT_STATUS_FAIL;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_pin_reply, *bd_addr,
+                                              accept, pin_len, *pin_code));
+  return BT_STATUS_SUCCESS;
+}
+
+static int ssp_reply(const RawAddress* bd_addr, bt_ssp_variant_t variant,
+                     uint8_t accept, uint32_t passkey) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+  if (variant == BT_SSP_VARIANT_PASSKEY_ENTRY) return BT_STATUS_FAIL;
+
+  do_in_main_thread(
+      FROM_HERE, base::BindOnce(btif_dm_ssp_reply, *bd_addr, variant, accept));
+  return BT_STATUS_SUCCESS;
+}
+
+static int read_energy_info() {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_read_energy_info));
+  return BT_STATUS_SUCCESS;
+}
+
+static void dump(int fd, const char** arguments) {
+  btif_debug_conn_dump(fd);
+  btif_debug_bond_event_dump(fd);
+  btif_debug_a2dp_dump(fd);
+  btif_debug_av_dump(fd);
+  bta_debug_av_dump(fd);
+  stack_debug_avdtp_api_dump(fd);
+  bluetooth::avrcp::AvrcpService::DebugDump(fd);
+  btif_debug_config_dump(fd);
+  BTA_HfClientDumpStatistics(fd);
+  wakelock_debug_dump(fd);
+  osi_allocator_debug_dump(fd);
+  alarm_debug_dump(fd);
+  bluetooth::csis::CsisClient::DebugDump(fd);
+  HearingAid::DebugDump(fd);
+  LeAudioClient::DebugDump(fd);
+  connection_manager::dump(fd);
+  bluetooth::bqr::DebugDump(fd);
+  if (bluetooth::shim::is_any_gd_enabled()) {
+    bluetooth::shim::Dump(fd, arguments);
+  } else {
+#if (BTSNOOP_MEM == TRUE)
+    btif_debug_btsnoop_dump(fd);
+#endif
+  }
+}
+
+static void dumpMetrics(std::string* output) {
+  bluetooth::common::BluetoothMetricsLogger::GetInstance()->WriteString(output);
+}
+
+static const void* get_profile_interface(const char* profile_id) {
+  LOG_INFO("%s: id = %s", __func__, profile_id);
+
+  /* sanity check */
+  if (!interface_ready()) return NULL;
+
+  /* check for supported profile interfaces */
+  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
+    return bluetooth::headset::GetInterface();
+
+  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
+    return btif_hf_client_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
+    return btif_sock_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_PAN_ID))
+    return btif_pan_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
+    return btif_av_get_src_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
+    return btif_av_get_sink_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
+    return btif_hh_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_HIDDEV_ID))
+    return btif_hd_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_SDP_CLIENT_ID))
+    return btif_sdp_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_GATT_ID))
+    return btif_gatt_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_AV_RC_ID))
+    return btif_rc_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
+    return btif_rc_ctrl_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_HEARING_AID_ID))
+    return btif_hearing_aid_get_interface();
+
+  if (is_profile(profile_id, BT_KEYSTORE_ID))
+    return bluetooth::bluetooth_keystore::getBluetoothKeystoreInterface();
+
+  if (is_profile(profile_id, BT_ACTIVITY_ATTRIBUTION_ID)) {
+    return bluetooth::activity_attribution::get_activity_attribution_instance();
+  }
+
+  if (is_profile(profile_id, BT_PROFILE_LE_AUDIO_ID))
+    return btif_le_audio_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_VC_ID))
+    return btif_volume_control_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_CSIS_CLIENT_ID))
+    return btif_csis_client_get_interface();
+
+  return NULL;
+}
+
+int dut_mode_configure(uint8_t enable) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+  if (!stack_manager_get_interface()->get_stack_is_running())
+    return BT_STATUS_NOT_READY;
+
+  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dut_mode_configure, enable));
+  return BT_STATUS_SUCCESS;
+}
+
+int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+  if (!btif_is_dut_mode()) return BT_STATUS_FAIL;
+
+  uint8_t* copy = (uint8_t*)osi_calloc(len);
+  memcpy(copy, buf, len);
+
+  do_in_main_thread(FROM_HERE,
+                    base::BindOnce(
+                        [](uint16_t opcode, uint8_t* buf, uint8_t len) {
+                          btif_dut_mode_send(opcode, buf, len);
+                          osi_free(buf);
+                        },
+                        opcode, copy, len));
+  return BT_STATUS_SUCCESS;
+}
+
+int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  switch (opcode) {
+    case HCI_BLE_TRANSMITTER_TEST:
+      if (len != 3) return BT_STATUS_PARM_INVALID;
+      do_in_main_thread(FROM_HERE, base::BindOnce(btif_ble_transmitter_test,
+                                                  buf[0], buf[1], buf[2]));
+      break;
+    case HCI_BLE_RECEIVER_TEST:
+      if (len != 1) return BT_STATUS_PARM_INVALID;
+      do_in_main_thread(FROM_HERE,
+                        base::BindOnce(btif_ble_receiver_test, buf[0]));
+      break;
+    case HCI_BLE_TEST_END:
+      do_in_main_thread(FROM_HERE, base::BindOnce(btif_ble_test_end));
+      break;
+    default:
+      return BT_STATUS_UNSUPPORTED;
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t* wakelock_os_callouts_saved = nullptr;
+
+static int acquire_wake_lock_cb(const char* lock_name) {
+  return do_in_jni_thread(
+      FROM_HERE, base::Bind(base::IgnoreResult(
+                                wakelock_os_callouts_saved->acquire_wake_lock),
+                            lock_name));
+}
+
+static int release_wake_lock_cb(const char* lock_name) {
+  return do_in_jni_thread(
+      FROM_HERE, base::Bind(base::IgnoreResult(
+                                wakelock_os_callouts_saved->release_wake_lock),
+                            lock_name));
+}
+
+static bt_os_callouts_t wakelock_os_callouts_jni = {
+    sizeof(wakelock_os_callouts_jni),
+    nullptr /* not used */,
+    acquire_wake_lock_cb,
+    release_wake_lock_cb,
+};
+
+static int set_os_callouts(bt_os_callouts_t* callouts) {
+  wakelock_os_callouts_saved = callouts;
+  wakelock_set_os_callouts(&wakelock_os_callouts_jni);
+  return BT_STATUS_SUCCESS;
+}
+
+static int config_clear(void) {
+  LOG_INFO("%s", __func__);
+  return btif_config_clear() ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+static bluetooth::avrcp::ServiceInterface* get_avrcp_service(void) {
+  return bluetooth::avrcp::AvrcpService::GetServiceInterface();
+}
+
+static std::string obfuscate_address(const RawAddress& address) {
+  return bluetooth::common::AddressObfuscator::GetInstance()->Obfuscate(
+      address);
+}
+
+static int get_metric_id(const RawAddress& address) {
+  return allocate_metric_id_from_metric_id_allocator(address);
+}
+
+static int set_dynamic_audio_buffer_size(int codec, int size) {
+  return btif_set_dynamic_audio_buffer_size(codec, size);
+}
+
+EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
+    sizeof(bluetoothInterface),
+    init,
+    enable,
+    disable,
+    cleanup,
+    get_adapter_properties,
+    get_adapter_property,
+    set_adapter_property,
+    get_remote_device_properties,
+    get_remote_device_property,
+    set_remote_device_property,
+    nullptr,
+    get_remote_services,
+    start_discovery,
+    cancel_discovery,
+    create_bond,
+    create_bond_out_of_band,
+    remove_bond,
+    cancel_bond,
+    get_connection_state,
+    pin_reply,
+    ssp_reply,
+    get_profile_interface,
+    dut_mode_configure,
+    dut_mode_send,
+    le_test_mode,
+    set_os_callouts,
+    read_energy_info,
+    dump,
+    dumpMetrics,
+    config_clear,
+    interop_database_clear,
+    interop_database_add,
+    get_avrcp_service,
+    obfuscate_address,
+    get_metric_id,
+    set_dynamic_audio_buffer_size,
+    generate_local_oob_data};
+
+// callback reporting helpers
+
+bt_property_t* property_deep_copy_array(int num_properties,
+                                        bt_property_t* properties) {
+  bt_property_t* copy = nullptr;
+  if (num_properties > 0) {
+    size_t content_len = 0;
+    for (int i = 0; i < num_properties; i++) {
+      auto len = properties[i].len;
+      if (len > 0) {
+        content_len += len;
+      }
+    }
+
+    copy = (bt_property_t*)osi_calloc((sizeof(bt_property_t) * num_properties) +
+                                      content_len);
+    ASSERT(copy != nullptr);
+    uint8_t* content = (uint8_t*)(copy + num_properties);
+
+    for (int i = 0; i < num_properties; i++) {
+      auto len = properties[i].len;
+      copy[i].type = properties[i].type;
+      copy[i].len = len;
+      if (len <= 0) {
+        continue;
+      }
+      copy[i].val = content;
+      memcpy(content, properties[i].val, len);
+      content += len;
+    }
+  }
+  return copy;
+}
+
+void invoke_adapter_state_changed_cb(bt_state_t state) {
+  do_in_jni_thread(FROM_HERE, base::BindOnce(
+                                  [](bt_state_t state) {
+                                    HAL_CBACK(bt_hal_cbacks,
+                                              adapter_state_changed_cb, state);
+                                  },
+                                  state));
+}
+
+void invoke_adapter_properties_cb(bt_status_t status, int num_properties,
+                                  bt_property_t* properties) {
+  do_in_jni_thread(FROM_HERE,
+                   base::BindOnce(
+                       [](bt_status_t status, int num_properties,
+                          bt_property_t* properties) {
+                         HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status,
+                                   num_properties, properties);
+                         if (properties) {
+                           osi_free(properties);
+                         }
+                       },
+                       status, num_properties,
+                       property_deep_copy_array(num_properties, properties)));
+}
+
+void invoke_remote_device_properties_cb(bt_status_t status, RawAddress bd_addr,
+                                        int num_properties,
+                                        bt_property_t* properties) {
+  do_in_jni_thread(
+      FROM_HERE, base::BindOnce(
+                     [](bt_status_t status, RawAddress bd_addr,
+                        int num_properties, bt_property_t* properties) {
+                       HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+                                 status, &bd_addr, num_properties, properties);
+                       if (properties) {
+                         osi_free(properties);
+                       }
+                     },
+                     status, bd_addr, num_properties,
+                     property_deep_copy_array(num_properties, properties)));
+}
+
+void invoke_device_found_cb(int num_properties, bt_property_t* properties) {
+  do_in_jni_thread(FROM_HERE,
+                   base::BindOnce(
+                       [](int num_properties, bt_property_t* properties) {
+                         HAL_CBACK(bt_hal_cbacks, device_found_cb,
+                                   num_properties, properties);
+                         if (properties) {
+                           osi_free(properties);
+                         }
+                       },
+                       num_properties,
+                       property_deep_copy_array(num_properties, properties)));
+}
+
+void invoke_discovery_state_changed_cb(bt_discovery_state_t state) {
+  do_in_jni_thread(FROM_HERE, base::BindOnce(
+                                  [](bt_discovery_state_t state) {
+                                    HAL_CBACK(bt_hal_cbacks,
+                                              discovery_state_changed_cb,
+                                              state);
+                                  },
+                                  state));
+}
+
+void invoke_pin_request_cb(RawAddress bd_addr, bt_bdname_t bd_name,
+                           uint32_t cod, bool min_16_digit) {
+  do_in_jni_thread(FROM_HERE, base::BindOnce(
+                                  [](RawAddress bd_addr, bt_bdname_t bd_name,
+                                     uint32_t cod, bool min_16_digit) {
+                                    HAL_CBACK(bt_hal_cbacks, pin_request_cb,
+                                              &bd_addr, &bd_name, cod,
+                                              min_16_digit);
+                                  },
+                                  bd_addr, bd_name, cod, min_16_digit));
+}
+
+void invoke_ssp_request_cb(RawAddress bd_addr, bt_bdname_t bd_name,
+                           uint32_t cod, bt_ssp_variant_t pairing_variant,
+                           uint32_t pass_key) {
+  do_in_jni_thread(FROM_HERE,
+                   base::BindOnce(
+                       [](RawAddress bd_addr, bt_bdname_t bd_name, uint32_t cod,
+                          bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
+                         HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr,
+                                   &bd_name, cod, pairing_variant, pass_key);
+                       },
+                       bd_addr, bd_name, cod, pairing_variant, pass_key));
+}
+
+void invoke_oob_data_request_cb(tBT_TRANSPORT t, bool valid, Octet16 c,
+                                Octet16 r, RawAddress raw_address,
+                                uint8_t address_type) {
+  LOG_INFO("%s", __func__);
+  bt_oob_data_t oob_data = {};
+  char* local_name;
+  BTM_ReadLocalDeviceName(&local_name);
+  for (int i = 0; i < BTM_MAX_LOC_BD_NAME_LEN; i++) {
+    oob_data.device_name[i] = local_name[i];
+  }
+
+  // Set the local address
+  int j = 5;
+  for (int i = 0; i < 6; i++) {
+    oob_data.address[i] = raw_address.address[j];
+    j--;
+  }
+  oob_data.address[6] = address_type;
+
+  // Each value (for C and R) is 16 octets in length
+  bool c_empty = true;
+  for (int i = 0; i < 16; i++) {
+    // C cannot be all 0s, if so then we want to fail
+    if (c[i] != 0) c_empty = false;
+    oob_data.c[i] = c[i];
+    // R is optional and may be empty
+    oob_data.r[i] = r[i];
+  }
+  oob_data.is_valid = valid && !c_empty;
+  // The oob_data_length is 2 octects in length.  The value includes the length
+  // of itself. 16 + 16 + 2 = 34 Data 0x0022 Little Endian order 0x2200
+  oob_data.oob_data_length[0] = 0;
+  oob_data.oob_data_length[1] = 34;
+  bt_status_t status = do_in_jni_thread(
+      FROM_HERE, base::BindOnce(
+                     [](tBT_TRANSPORT t, bt_oob_data_t oob_data) {
+                       HAL_CBACK(bt_hal_cbacks, generate_local_oob_data_cb, t,
+                                 oob_data);
+                     },
+                     t, oob_data));
+  if (status != BT_STATUS_SUCCESS) {
+    LOG_ERROR("%s: Failed to call callback!", __func__);
+  }
+}
+
+void invoke_bond_state_changed_cb(bt_status_t status, RawAddress bd_addr,
+                                  bt_bond_state_t state, int fail_reason) {
+  do_in_jni_thread(FROM_HERE, base::BindOnce(
+                                  [](bt_status_t status, RawAddress bd_addr,
+                                     bt_bond_state_t state, int fail_reason) {
+                                    HAL_CBACK(bt_hal_cbacks,
+                                              bond_state_changed_cb, status,
+                                              &bd_addr, state, fail_reason);
+                                  },
+                                  status, bd_addr, state, fail_reason));
+}
+
+void invoke_acl_state_changed_cb(bt_status_t status, RawAddress bd_addr,
+                                 bt_acl_state_t state, int transport_link_type,
+                                 bt_hci_error_code_t hci_reason) {
+  do_in_jni_thread(
+      FROM_HERE,
+      base::BindOnce(
+          [](bt_status_t status, RawAddress bd_addr, bt_acl_state_t state,
+             int transport_link_type, bt_hci_error_code_t hci_reason) {
+            HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, status, &bd_addr,
+                      state, transport_link_type, hci_reason);
+          },
+          status, bd_addr, state, transport_link_type, hci_reason));
+}
+
+void invoke_thread_evt_cb(bt_cb_thread_evt event) {
+  do_in_jni_thread(FROM_HERE, base::BindOnce(
+                                  [](bt_cb_thread_evt event) {
+                                    HAL_CBACK(bt_hal_cbacks, thread_evt_cb,
+                                              event);
+                                    if (event == DISASSOCIATE_JVM) {
+                                      bt_hal_cbacks = NULL;
+                                    }
+                                  },
+                                  event));
+}
+
+void invoke_le_test_mode_cb(bt_status_t status, uint16_t count) {
+  do_in_jni_thread(FROM_HERE, base::BindOnce(
+                                  [](bt_status_t status, uint16_t count) {
+                                    HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,
+                                              status, count);
+                                  },
+                                  status, count));
+}
+
+// takes ownership of |uid_data|
+void invoke_energy_info_cb(bt_activity_energy_info energy_info,
+                           bt_uid_traffic_t* uid_data) {
+  do_in_jni_thread(
+      FROM_HERE,
+      base::BindOnce(
+          [](bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data) {
+            HAL_CBACK(bt_hal_cbacks, energy_info_cb, &energy_info, uid_data);
+            osi_free(uid_data);
+          },
+          energy_info, uid_data));
+}
+
+void invoke_link_quality_report_cb(uint64_t timestamp, int report_id, int rssi,
+                                   int snr, int retransmission_count,
+                                   int packets_not_receive_count,
+                                   int negative_acknowledgement_count) {
+  do_in_jni_thread(
+      FROM_HERE,
+      base::BindOnce(
+          [](uint64_t timestamp, int report_id, int rssi, int snr,
+             int retransmission_count, int packets_not_receive_count,
+             int negative_acknowledgement_count) {
+            HAL_CBACK(bt_hal_cbacks, link_quality_report_cb, timestamp,
+                      report_id, rssi, snr, retransmission_count,
+                      packets_not_receive_count,
+                      negative_acknowledgement_count);
+          },
+          timestamp, report_id, rssi, snr, retransmission_count,
+          packets_not_receive_count, negative_acknowledgement_count));
+}
diff --git a/system/service/hal/bluetooth_interface.cc b/system/service/hal/bluetooth_interface.cc
index 391f6a4560372984739ad9c19d161f97c67643b6..0382b5e5a3258fe13a9ef3907f0cc924ee829ceb 100644
--- a/system/service/hal/bluetooth_interface.cc
+++ b/system/service/hal/bluetooth_interface.cc
@@ -18,6 +18,7 @@
 
 #include <base/logging.h>
 #include <base/observer_list.h>
+#include <dlfcn.h>
 
 #include <mutex>
 #include <shared_mutex>
@@ -235,6 +236,43 @@ bt_os_callouts_t bt_os_callouts = {sizeof(bt_os_callouts_t),
                                    SetWakeAlarmCallout, AcquireWakeLockCallout,
                                    ReleaseWakeLockCallout};
 
+constexpr char kLibbluetooth[] = "libbluetooth.so";
+constexpr char kBluetoothInterfaceSym[] = "bluetoothInterface";
+
+int hal_util_load_bt_library_from_dlib(const bt_interface_t** interface) {
+  bt_interface_t* itf{nullptr};
+
+  // Always try to load the default Bluetooth stack on GN builds.
+  void* handle = dlopen(kLibbluetooth, RTLD_NOW);
+  if (!handle) {
+    const char* err_str = dlerror();
+    LOG(ERROR) << __func__ << ": failed to load bluetooth library, error="
+               << (err_str ? err_str : "error unknown");
+    goto error;
+  }
+
+  // Get the address of the bt_interface_t.
+  itf = (bt_interface_t*)dlsym(handle, kBluetoothInterfaceSym);
+  if (!itf) {
+    LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library "
+               << kBluetoothInterfaceSym;
+    goto error;
+  }
+
+  // Success.
+  LOG(INFO) << __func__ << " loaded HAL path=" << kLibbluetooth
+            << " btinterface=" << itf << " handle=" << handle;
+
+  *interface = itf;
+  return 0;
+
+error:
+  *interface = NULL;
+  if (handle) dlclose(handle);
+
+  return -EINVAL;
+}
+
 }  // namespace
 
 // BluetoothInterface implementation for production.
@@ -266,7 +304,7 @@ class BluetoothInterfaceImpl : public BluetoothInterface {
   bool Initialize() {
     // Load the Bluetooth shared library module.
     const bt_interface_t* interface;
-    int status = hal_util_load_bt_library(&interface);
+    int status = hal_util_load_bt_library_from_dlib(&interface);
     if (status) {
       LOG(ERROR) << "Failed to open the Bluetooth module";
       return false;
diff --git a/system/test/suite/Android.bp b/system/test/suite/Android.bp
index 40b8221d1b7724b36d8db09f0c15519232609555..5dc6bcc4cfc2e781f8719e2153c62a966d0e6368 100644
--- a/system/test/suite/Android.bp
+++ b/system/test/suite/Android.bp
@@ -12,8 +12,16 @@ cc_test {
     name: "net_test_bluetooth",
     test_suites: ["device-tests"],
     defaults: ["fluoride_defaults"],
-    include_dirs: ["packages/modules/Bluetooth/system"],
+    include_dirs: [
+        "packages/modules/Bluetooth/system",
+        "packages/modules/Bluetooth/system/gd",
+        "packages/modules/Bluetooth/system/include",
+        "packages/modules/Bluetooth/system/stack/include",
+    ],
     srcs: [
+        ":TestCommonMockFunctions",
+        ":TestMockBluetoothInterface",
+        ":TestMockDevice",
         "adapter/adapter_unittest.cc",
         "adapter/bluetooth_test.cc",
         "gatt/gatt_test.cc",
@@ -39,8 +47,16 @@ cc_test {
 cc_test {
     name: "net_test_rfcomm_suite",
     defaults: ["fluoride_defaults"],
-    include_dirs: ["packages/modules/Bluetooth/system"],
+    include_dirs: [
+        "packages/modules/Bluetooth/system",
+        "packages/modules/Bluetooth/system/gd",
+        "packages/modules/Bluetooth/system/include",
+        "packages/modules/Bluetooth/system/stack/include",
+    ],
     srcs: [
+        ":TestMockBluetoothInterface",
+        ":TestMockDevice",
+        ":TestCommonMockFunctions",
         "adapter/bluetooth_test.cc",
         "rfcomm/rfcomm_test.cc",
         "rfcomm/rfcomm_unittest.cc",