diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index f2407fc85aa710293e86417fe2c0faaf31d29159..a7636ecfe7da44ce567bfb9e3b98397b8725131b 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -929,6 +929,11 @@ final class RemoteDevices {
     })
     void aclStateChangeCallback(int status, byte[] address, int newState,
                                 int transportLinkType, int hciReason) {
+        if (status != AbstractionLayer.BT_STATUS_SUCCESS) {
+            debugLog("aclStateChangeCallback status is " + status + ", skipping");
+            return;
+        }
+
         BluetoothDevice device = getDevice(address);
 
         if (device == null) {
diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc
index 65389ad1ff1853f8246120a5e29ec0e154b44db4..8f4809aef51643dc63b0c23f68fe8445eaaa5a75 100644
--- a/system/bta/dm/bta_dm_act.cc
+++ b/system/bta/dm/bta_dm_act.cc
@@ -2506,6 +2506,23 @@ void BTA_dm_acl_up(const RawAddress bd_addr, tBT_TRANSPORT transport) {
   do_in_main_thread(FROM_HERE, base::Bind(bta_dm_acl_up, bd_addr, transport));
 }
 
+static void bta_dm_acl_up_failed(const RawAddress bd_addr,
+                                 tBT_TRANSPORT transport, tHCI_STATUS status) {
+  if (bta_dm_cb.p_sec_cback) {
+    tBTA_DM_SEC conn = {};
+    conn.link_up_failed.bd_addr = bd_addr;
+    conn.link_up_failed.transport_link_type = transport;
+    conn.link_up_failed.status = status;
+    bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_FAILED_EVT, &conn);
+  }
+}
+
+void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport,
+                          tHCI_STATUS status) {
+  do_in_main_thread(
+      FROM_HERE, base::Bind(bta_dm_acl_up_failed, bd_addr, transport, status));
+}
+
 static void bta_dm_acl_down(const RawAddress& bd_addr,
                             tBT_TRANSPORT transport) {
   bool issue_unpair_cb = false;
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index 58c4c28551a0016357e16a3f4d84715726202dee..84e3f609d751a9af9d22dbb0bd862e77b1d2fcc9 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -225,6 +225,7 @@ typedef enum : uint8_t {
   BTA_DM_BLE_SC_CR_LOC_OOB_EVT = 31, /* SMP SC Create Local OOB request event */
   BTA_DM_REPORT_BONDING_EVT = 32,    /*handle for pin or key missing*/
   BTA_DM_LE_ADDR_ASSOC_EVT = 33,     /* identity address association event */
+  BTA_DM_LINK_UP_FAILED_EVT = 34,    /* Create connection failed event */
 } tBTA_DM_SEC_EVT;
 
 /* Structure associated with BTA_DM_PIN_REQ_EVT */
@@ -313,10 +314,18 @@ typedef struct {
   tBT_TRANSPORT transport_link_type;
 } tBTA_DM_LINK_UP;
 
+/* Structure associated with BTA_DM_LINK_UP_FAILED_EVT */
+typedef struct {
+  RawAddress bd_addr; /* BD address peer device. */
+  tBT_TRANSPORT transport_link_type;
+  tHCI_STATUS status; /* The HCI error code associated with this event */
+} tBTA_DM_LINK_UP_FAILED;
+
 /* Structure associated with BTA_DM_LINK_DOWN_EVT */
 typedef struct {
   RawAddress bd_addr; /* BD address peer device. */
   tBT_TRANSPORT transport_link_type;
+  tHCI_STATUS status;
 } tBTA_DM_LINK_DOWN;
 
 #define BTA_AUTH_SP_YES                                                       \
@@ -393,7 +402,8 @@ typedef struct {
 typedef union {
   tBTA_DM_PIN_REQ pin_req;        /* PIN request. */
   tBTA_DM_AUTH_CMPL auth_cmpl;    /* Authentication complete indication. */
-  tBTA_DM_LINK_UP link_up;        /* ACL connection down event */
+  tBTA_DM_LINK_UP link_up;        /* ACL connection up event */
+  tBTA_DM_LINK_UP_FAILED link_up_failed; /* ACL connection up failure event */
   tBTA_DM_LINK_DOWN link_down;    /* ACL connection down event */
   tBTA_DM_SP_CFM_REQ cfm_req;     /* user confirm request */
   tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */
diff --git a/system/bta/include/bta_dm_acl.h b/system/bta/include/bta_dm_acl.h
index aaaa94eb35aac55e5de7ebf822fa57bd40adc2a0..a49d8ee8261758a9029debea4aa410df8acb243a 100644
--- a/system/bta/include/bta_dm_acl.h
+++ b/system/bta/include/bta_dm_acl.h
@@ -25,6 +25,8 @@
 #include "types/raw_address.h"
 
 void BTA_dm_acl_up(const RawAddress bd_addr, tBT_TRANSPORT transport);
+void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport,
+                          tHCI_STATUS hci_status);
 void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport);
 void BTA_dm_report_role_change(const RawAddress bd_addr, tHCI_ROLE new_role,
                                tHCI_STATUS hci_status);
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 9b6e1d04e8cc51df5c4c2ea03be258511ead5802..e6029ba68d6a8485f1e1848a8f4ae52a35f458a0 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -1828,11 +1828,19 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) {
           (int)p_data->link_up.transport_link_type, HCI_SUCCESS);
       break;
 
+    case BTA_DM_LINK_UP_FAILED_EVT:
+      invoke_acl_state_changed_cb(
+          BT_STATUS_FAIL, p_data->link_up_failed.bd_addr,
+          BT_ACL_STATE_DISCONNECTED, p_data->link_up_failed.transport_link_type,
+          p_data->link_up_failed.status);
+      break;
+
     case BTA_DM_LINK_DOWN_EVT:
       bd_addr = p_data->link_down.bd_addr;
       btm_set_bond_type_dev(p_data->link_down.bd_addr,
                             tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN);
       btif_av_acl_disconnected(bd_addr);
+
       invoke_acl_state_changed_cb(
           BT_STATUS_SUCCESS, bd_addr, BT_ACL_STATE_DISCONNECTED,
           (int)p_data->link_down.transport_link_type,
diff --git a/system/stack/acl/ble_acl.cc b/system/stack/acl/ble_acl.cc
index 18759f9b0e45dacf7165c678a544fb1cc2c91019..ea651d9e2f9df44fbb04e3020b0399d819c4189b 100644
--- a/system/stack/acl/ble_acl.cc
+++ b/system/stack/acl/ble_acl.cc
@@ -161,6 +161,8 @@ void acl_ble_connection_fail(const tBLE_BD_ADDR& address_with_type,
   }
   btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, &address_with_type.bda,
                                 status);
+
+  btm_acl_create_failed(address_with_type.bda, BT_TRANSPORT_LE, status);
 }
 
 void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval,
diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc
index 0c51dae30dd77a5f79c31d0adadc6f8e1f8d1046..98bdced377c3e3dc78a52763fbd413f26cf66dd8 100644
--- a/system/stack/acl/btm_acl.cc
+++ b/system/stack/acl/btm_acl.cc
@@ -441,6 +441,11 @@ void btm_acl_created(const RawAddress& bda, uint16_t hci_handle,
   }
 }
 
+void btm_acl_create_failed(const RawAddress& bda, tBT_TRANSPORT transport,
+                           tHCI_STATUS hci_status) {
+  BTA_dm_acl_up_failed(bda, transport, hci_status);
+}
+
 void btm_acl_update_conn_addr(uint16_t handle, const RawAddress& address) {
   tACL_CONN* p_acl = internal_.acl_get_connection_from_handle(handle);
   if (p_acl == nullptr) {
@@ -2570,6 +2575,8 @@ void on_acl_br_edr_failed(const RawAddress& bda, tHCI_STATUS status) {
   delayed_role_change_ = nullptr;
   btm_acl_set_paging(false);
   l2c_link_hci_conn_comp(status, HCI_INVALID_HANDLE, bda);
+
+  btm_acl_create_failed(bda, BT_TRANSPORT_BR_EDR, status);
 }
 
 void btm_acl_connected(const RawAddress& bda, uint16_t handle,
diff --git a/system/stack/include/acl_api.h b/system/stack/include/acl_api.h
index 8faf15c748a206a820bb714c7b2fad0ee1e8949c..cc7d4587829dfb4ff2b69fc538e437d6cc6d70f4 100644
--- a/system/stack/include/acl_api.h
+++ b/system/stack/include/acl_api.h
@@ -292,6 +292,9 @@ bool BTM_ReadPowerMode(const RawAddress& remote_bda, tBTM_PM_MODE* p_mode);
 void btm_acl_created(const RawAddress& bda, uint16_t hci_handle,
                      tHCI_ROLE link_role, tBT_TRANSPORT transport);
 
+void btm_acl_create_failed(const RawAddress& bda, tBT_TRANSPORT transport,
+                           tHCI_STATUS reason);
+
 void btm_acl_removed(uint16_t handle);
 
 void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason,
diff --git a/system/test/mock/mock_bta_dm_act.cc b/system/test/mock/mock_bta_dm_act.cc
index f77e90b9b5334b3b91ae956b22972693dad3689b..b64f5f62fc6de231792522db51f777554c52edfe 100644
--- a/system/test/mock/mock_bta_dm_act.cc
+++ b/system/test/mock/mock_bta_dm_act.cc
@@ -42,6 +42,7 @@ namespace bta_dm_act {
 struct BTA_DmSetVisibility BTA_DmSetVisibility;
 struct BTA_dm_acl_down BTA_dm_acl_down;
 struct BTA_dm_acl_up BTA_dm_acl_up;
+struct BTA_dm_acl_up_failed BTA_dm_acl_up_failed;
 struct BTA_dm_notify_remote_features_complete
     BTA_dm_notify_remote_features_complete;
 struct BTA_dm_on_hw_off BTA_dm_on_hw_off;
@@ -119,6 +120,11 @@ void BTA_dm_acl_up(const RawAddress bd_addr, tBT_TRANSPORT transport) {
   mock_function_count_map[__func__]++;
   test::mock::bta_dm_act::BTA_dm_acl_up(bd_addr, transport);
 }
+void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport,
+                          tHCI_STATUS hci_status) {
+  mock_function_count_map[__func__]++;
+  test::mock::bta_dm_act::BTA_dm_acl_up_failed(bd_addr, transport, hci_status);
+}
 void BTA_dm_notify_remote_features_complete(const RawAddress bd_addr) {
   mock_function_count_map[__func__]++;
   test::mock::bta_dm_act::BTA_dm_notify_remote_features_complete(bd_addr);
diff --git a/system/test/mock/mock_bta_dm_act.h b/system/test/mock/mock_bta_dm_act.h
index af586006e615eea1340a05924bfb993e1fddfed6..755e04d1815ad60ad342b1785901d37f44f73f34 100644
--- a/system/test/mock/mock_bta_dm_act.h
+++ b/system/test/mock/mock_bta_dm_act.h
@@ -99,6 +99,21 @@ struct BTA_dm_acl_up {
 };
 extern struct BTA_dm_acl_up BTA_dm_acl_up;
 
+// Name: BTA_dm_acl_up_failed
+// Params: const RawAddress bd_addr, tBT_TRANSPORT transport, tHCI_STATUS
+// hci_status Return: void
+struct BTA_dm_acl_up_failed {
+  std::function<void(const RawAddress bd_addr, tBT_TRANSPORT transport,
+                     tHCI_STATUS hci_status)>
+      body{[](const RawAddress bd_addr, tBT_TRANSPORT transport,
+              tHCI_STATUS hci_status) {}};
+  void operator()(const RawAddress bd_addr, tBT_TRANSPORT transport,
+                  tHCI_STATUS hci_status) {
+    body(bd_addr, transport, hci_status);
+  };
+};
+extern struct BTA_dm_acl_up_failed BTA_dm_acl_up_failed;
+
 // Name: BTA_dm_notify_remote_features_complete
 // Params: const RawAddress bd_addr
 // Return: void