diff --git a/android/app/jni/com_android_bluetooth_hid_host.cpp b/android/app/jni/com_android_bluetooth_hid_host.cpp
index b21fc9c5b5b35f894173c20e7040e064c316e28f..f60a6a2d735c84e1af4dde3944607370f4b77ab6 100644
--- a/android/app/jni/com_android_bluetooth_hid_host.cpp
+++ b/android/app/jni/com_android_bluetooth_hid_host.cpp
@@ -271,7 +271,8 @@ static jboolean connectHidNative(JNIEnv* env, jobject /* object */,
 }
 
 static jboolean disconnectHidNative(JNIEnv* env, jobject /* object */,
-                                    jbyteArray address) {
+                                    jbyteArray address,
+                                    jboolean reconnect_allowed) {
   jbyte* addr;
   jboolean ret = JNI_TRUE;
   if (!sBluetoothHidInterface) return JNI_FALSE;
@@ -282,7 +283,8 @@ static jboolean disconnectHidNative(JNIEnv* env, jobject /* object */,
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothHidInterface->disconnect((RawAddress*)addr);
+  bt_status_t status =
+      sBluetoothHidInterface->disconnect((RawAddress*)addr, reconnect_allowed);
   if (status != BT_STATUS_SUCCESS) {
     log::error("Failed disconnect hid channel, status: {}",
                bt_status_text(status));
@@ -500,7 +502,7 @@ int register_com_android_bluetooth_hid_host(JNIEnv* env) {
       {"initializeNative", "()V", (void*)initializeNative},
       {"cleanupNative", "()V", (void*)cleanupNative},
       {"connectHidNative", "([B)Z", (void*)connectHidNative},
-      {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative},
+      {"disconnectHidNative", "([BZ)Z", (void*)disconnectHidNative},
       {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative},
       {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative},
       {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative},
diff --git a/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java b/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java
index 3a717023ca0c7bab4d58244874b2fd2aeab90762..6d6c5b404336f167d100bf1d726a08b229931fa5 100644
--- a/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java
@@ -64,8 +64,8 @@ public class HidHostNativeInterface {
         return connectHidNative(address);
     }
 
-    boolean disconnectHid(byte[] address) {
-        return disconnectHidNative(address);
+    boolean disconnectHid(byte[] address, boolean reconnectAllowed) {
+        return disconnectHidNative(address, reconnectAllowed);
     }
 
     boolean getProtocolMode(byte[] address) {
@@ -168,7 +168,7 @@ public class HidHostNativeInterface {
 
     private native boolean connectHidNative(byte[] btAddress);
 
-    private native boolean disconnectHidNative(byte[] btAddress);
+    private native boolean disconnectHidNative(byte[] btAddress, boolean reconnectAllowed);
 
     private native boolean getProtocolModeNative(byte[] btAddress);
 
diff --git a/android/app/src/com/android/bluetooth/hid/HidHostService.java b/android/app/src/com/android/bluetooth/hid/HidHostService.java
index 433ab301606aa0361d431925f50c40dbfcbf4a65..745aedd2cc19d4fa069fae2b5fd4fde907c8d108 100644
--- a/android/app/src/com/android/bluetooth/hid/HidHostService.java
+++ b/android/app/src/com/android/bluetooth/hid/HidHostService.java
@@ -201,7 +201,10 @@ public class HidHostService extends ProfileService {
                     break;
                 case MESSAGE_DISCONNECT: {
                         BluetoothDevice device = (BluetoothDevice) msg.obj;
-                        if (!mNativeInterface.disconnectHid(getByteAddress(device))) {
+                        int connectionPolicy = getConnectionPolicy(device);
+                        boolean reconnectAllowed =
+                                connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+                        if (!mNativeInterface.disconnectHid(getByteAddress(device), reconnectAllowed)) {
                             broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
                             broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
                             break;
@@ -352,9 +355,7 @@ public class HidHostService extends ProfileService {
         }
     };
 
-    /**
-     * Handlers for incoming service calls
-     */
+    /** Handlers for incoming service calls */
     @VisibleForTesting
     static class BluetoothHidHostBinder extends IBluetoothHidHost.Stub
             implements IProfileServiceBinder {
diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h
index 7dd5aa1cdcf8d32151594901db1e418adf90d03b..59d39cbde84cda21092a8a6d49774eec8aa0d6c7 100644
--- a/system/btif/include/btif_hh.h
+++ b/system/btif/include/btif_hh.h
@@ -109,6 +109,7 @@ typedef struct {
   uint8_t dev_handle;
   tAclLinkSpec link_spec;
   tBTA_HH_ATTR_MASK attr_mask;
+  bool reconnect_allowed;
 } btif_hh_added_device_t;
 
 /**
@@ -133,7 +134,8 @@ extern btif_hh_cb_t btif_hh_cb;
 btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle);
 void btif_hh_remove_device(const tAclLinkSpec& link_spec);
 bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec,
-                           tBTA_HH_ATTR_MASK attr_mask);
+                           tBTA_HH_ATTR_MASK attr_mask,
+                           bool reconnect_allowed);
 bt_status_t btif_hh_virtual_unplug(const tAclLinkSpec* link_spec);
 void btif_hh_disconnect(const tAclLinkSpec* link_spec);
 void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type,
diff --git a/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h
index 394cd5b5b7da4f58ecc414548d2feefb8c1555b4..51600d535b31b31cd7b3edfd0352816d36e66a61 100644
--- a/system/btif/include/btif_storage.h
+++ b/system/btif/include/btif_storage.h
@@ -215,6 +215,29 @@ void btif_storage_load_le_devices(void);
  ******************************************************************************/
 bt_status_t btif_storage_load_bonded_devices(void);
 
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_hid_connection_policy
+ *
+ * Description      Stores connection policy info in nvram
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_hid_connection_policy(const RawAddress& addr,
+                                                   bool reconnect_allowed);
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_hid_connection_policy
+ *
+ * Description      get connection policy info from nvram
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_hid_connection_policy(const RawAddress& addr,
+                                                   bool* reconnect_allowed);
+
 /*******************************************************************************
  *
  * Function         btif_storage_add_hid_device_info
diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc
index 56887822a07514669c23e62c614b37de12a98d81..ccd67812ceae90af10023aa3e139a77c11fa8afb 100644
--- a/system/btif/src/btif_hh.cc
+++ b/system/btif/src/btif_hh.cc
@@ -280,6 +280,24 @@ static void sync_lockstate_on_connect(btif_hh_device_t* p_dev) {
   }
 }
 
+/*******************************************************************************
+ *
+ * Function         btif_hh_find_added_dev
+ *
+ * Description      Return the added device pointer of the specified address
+ *
+ * Returns          Added device entry
+ ******************************************************************************/
+btif_hh_added_device_t* btif_hh_find_added_dev(const RawAddress& addr) {
+  for (int i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+    btif_hh_added_device_t* added_dev = &btif_hh_cb.added_devices[i];
+    if (added_dev->link_spec.addrt.bda == addr) {
+      return added_dev;
+    }
+  }
+  return nullptr;
+}
+
 /*******************************************************************************
  *
  * Function         btif_hh_find_connected_dev_by_handle
@@ -390,9 +408,38 @@ static void hh_connect_complete(uint8_t handle, tAclLinkSpec& link_spec,
   HAL_CBACK(bt_hh_callbacks, connection_state_cb, &link_spec.addrt.bda, state);
 }
 
+static bool hh_connection_allowed(const RawAddress& bda) {
+  /* Accept connection only if reconnection is allowed for the known device, or
+   * outgoing connection was requested */
+  btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(bda);
+  if (added_dev != nullptr && added_dev->reconnect_allowed) {
+    LOG_VERBOSE("Connection allowed %s", ADDRESS_TO_LOGGABLE_CSTR(bda));
+    return true;
+  } else if (btif_hh_cb.pending_link_spec.addrt.bda == bda) {
+    LOG_VERBOSE("Device connection was pending for: %s, status: %s",
+                ADDRESS_TO_LOGGABLE_CSTR(bda),
+                btif_hh_status_text(btif_hh_cb.status).c_str());
+    return true;
+  }
+
+  return false;
+}
+
 static void hh_open_handler(tBTA_HH_CONN& conn) {
   log::debug("status = {}, handle = {}", conn.status, conn.handle);
 
+  if (!hh_connection_allowed(conn.link_spec.addrt.bda)) {
+    LOG_WARN("Reject unexpected incoming HID Connection, device: %s",
+             ADDRESS_TO_LOGGABLE_CSTR(conn.link_spec));
+    btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_handle(conn.handle);
+    if (p_dev != nullptr) {
+      p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+    }
+
+    hh_connect_complete(conn.handle, conn.link_spec, BTIF_HH_DEV_DISCONNECTED);
+    return;
+  }
+
   HAL_CBACK(bt_hh_callbacks, connection_state_cb,
             (RawAddress*)&conn.link_spec.addrt.bda, BTHH_CONN_STATE_CONNECTING);
   btif_hh_cb.pending_link_spec = {};
@@ -447,7 +494,8 @@ static void hh_open_handler(tBTA_HH_CONN& conn) {
  * Returns          true if add successfully, otherwise false.
  ******************************************************************************/
 bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec,
-                           tBTA_HH_ATTR_MASK attr_mask) {
+                           tBTA_HH_ATTR_MASK attr_mask,
+                           bool reconnect_allowed) {
   int i;
   for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
     if (btif_hh_cb.added_devices[i].link_spec.addrt.bda ==
@@ -458,10 +506,12 @@ bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec,
   }
   for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
     if (btif_hh_cb.added_devices[i].link_spec.addrt.bda.IsEmpty()) {
-      log::warn("Added device {}", ADDRESS_TO_LOGGABLE_STR(link_spec));
+      log::warn("Added device {} reconnection allowed: {}",
+              ADDRESS_TO_LOGGABLE_STR(link_spec), reconnect_allowed);
       btif_hh_cb.added_devices[i].link_spec = link_spec;
       btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
       btif_hh_cb.added_devices[i].attr_mask = attr_mask;
+      btif_hh_cb.added_devices[i].reconnect_allowed = reconnect_allowed;
       return true;
     }
   }
@@ -1012,7 +1062,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {
                                 p_data->dscp_info.version,
                                 p_data->dscp_info.ctry_code, len,
                                 p_data->dscp_info.descriptor.dsc_list);
-        if (btif_hh_add_added_dev(p_dev->link_spec, p_dev->attr_mask)) {
+        if (btif_hh_add_added_dev(p_dev->link_spec, p_dev->attr_mask, true)) {
           tBTA_HH_DEV_DSCP_INFO dscp_info;
           bt_status_t ret;
           btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info);
@@ -1029,6 +1079,8 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {
               p_data->dscp_info.ssr_min_tout, len,
               p_data->dscp_info.descriptor.dsc_list);
 
+          btif_storage_set_hid_connection_policy(p_dev->link_spec.addrt.bda, true);
+
           ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret);
           log::warn("BTA_HH_GET_DSCP_EVT: Called add device");
 
@@ -1334,6 +1386,13 @@ static bt_status_t connect(RawAddress* bd_addr) {
   link_spec.addrt.type = BLE_ADDR_PUBLIC;
   link_spec.transport = BT_TRANSPORT_AUTO;
 
+  /* If the device was already added, ensure that reconnections are allowed */
+  btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(*bd_addr);
+  if (added_dev != nullptr && !added_dev->reconnect_allowed) {
+    added_dev->reconnect_allowed = true;
+    btif_storage_set_hid_connection_policy(*bd_addr, true);
+  }
+
   p_dev = btif_hh_find_connected_dev_by_bda(link_spec);
   if (p_dev) {
     if (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED ||
@@ -1361,7 +1420,7 @@ static bt_status_t connect(RawAddress* bd_addr) {
  * Returns         bt_status_t
  *
  ******************************************************************************/
-static bt_status_t disconnect(RawAddress* bd_addr) {
+static bt_status_t disconnect(RawAddress* bd_addr, bool reconnect_allowed) {
   CHECK_BTHH_INIT();
   log::verbose("BTHH");
   btif_hh_device_t* p_dev;
@@ -1377,6 +1436,16 @@ static bt_status_t disconnect(RawAddress* bd_addr) {
   link_spec.addrt.type = BLE_ADDR_PUBLIC;
   link_spec.transport = BT_TRANSPORT_AUTO;
 
+  if (!reconnect_allowed) {
+    LOG_INFO("Incoming reconnections disabled for device %s",
+             ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
+    btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(*bd_addr);
+    if (added_dev != nullptr && added_dev->reconnect_allowed) {
+      added_dev->reconnect_allowed = false;
+      btif_storage_set_hid_connection_policy(added_dev->link_spec.addrt.bda, false);
+    }
+  }
+
   p_dev = btif_hh_find_connected_dev_by_bda(link_spec);
   if (!p_dev) {
     log::error("Error, device {} not opened.",
@@ -1541,9 +1610,10 @@ static bt_status_t set_info(RawAddress* bd_addr, bthh_hid_info_t hid_info) {
   link_spec.addrt.type = BLE_ADDR_PUBLIC;
   link_spec.transport = BT_TRANSPORT_AUTO;
 
-  if (btif_hh_add_added_dev(link_spec, hid_info.attr_mask)) {
+  if (btif_hh_add_added_dev(link_spec, hid_info.attr_mask, true)) {
     BTA_HhAddDev(link_spec, hid_info.attr_mask, hid_info.sub_class,
                  hid_info.app_id, dscp_info);
+    btif_storage_set_hid_connection_policy(*bd_addr, true);
   }
 
   osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list);
diff --git a/system/btif/src/btif_profile_storage.cc b/system/btif/src/btif_profile_storage.cc
index 2884fb15d0d31f9bbd0309a83e94741f6d3a8b95..2676c36afb2e6b71aa0f05e2850145597ef3e99c 100644
--- a/system/btif/src/btif_profile_storage.cc
+++ b/system/btif/src/btif_profile_storage.cc
@@ -80,6 +80,49 @@ using namespace bluetooth;
    STORAGE_HID_VERSION_SIZE + 1 + STORAGE_HID_CTRY_CODE_SIZE + 1 +    \
    STORAGE_HID_DESC_LEN_SIZE + 1 + STORAGE_HID_DESC_MAX_SIZE + 1)
 
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_hid_connection_policy
+ *
+ * Description      Stores connection policy info in nvram
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_hid_connection_policy(const RawAddress& addr,
+                                                   bool reconnect_allowed) {
+  std::string bdstr = addr.ToString();
+
+  if (btif_config_set_int(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED,
+                          reconnect_allowed)) {
+    return BT_STATUS_SUCCESS;
+  } else {
+    return BT_STATUS_FAIL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_hid_connection_policy
+ *
+ * Description      get connection policy info from nvram
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_hid_connection_policy(const RawAddress& addr,
+                                                   bool* reconnect_allowed) {
+  std::string bdstr = addr.ToString();
+
+  // For backward compatibility, assume that the reconnection is allowed in the
+  // absence of the key
+  int value = 1;
+  btif_config_get_int(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED, &value);
+  *reconnect_allowed = (value != 0);
+
+  return BT_STATUS_SUCCESS;
+}
+
 /*******************************************************************************
  *
  * Function         btif_storage_add_hid_device_info
@@ -181,11 +224,14 @@ bt_status_t btif_storage_load_bonded_hid_info(void) {
                           (uint8_t*)dscp_info.descriptor.dsc_list, &len);
     }
 
+    bool reconnect_allowed = false;
+    btif_storage_get_hid_connection_policy(bd_addr, &reconnect_allowed);
+
     // add extracted information to BTA HH
     link_spec.addrt.bda = bd_addr;
     link_spec.addrt.type = BLE_ADDR_PUBLIC;
     link_spec.transport = BT_TRANSPORT_AUTO;
-    if (btif_hh_add_added_dev(link_spec, attr_mask)) {
+    if (btif_hh_add_added_dev(link_spec, attr_mask, reconnect_allowed)) {
       BTA_HhAddDev(link_spec, attr_mask, sub_class, app_id, dscp_info);
     }
   }
@@ -217,6 +263,7 @@ bt_status_t btif_storage_remove_hid_info(const RawAddress& remote_bd_addr) {
   btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_SSR_MAX_LATENCY);
   btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_SSR_MIN_TIMEOUT);
   btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_DESCRIPTOR);
+  btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED);
   btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_REPORT);
   btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_REPORT_VERSION);
   return BT_STATUS_SUCCESS;
diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs
index 2e0cf877c40670809cc7040b59be7ccc686618ba..4b4eb4c70a085d3c57937316d57ebaba7ddd1b4c 100644
--- a/system/gd/rust/linux/stack/src/bluetooth.rs
+++ b/system/gd/rust/linux/stack/src/bluetooth.rs
@@ -2718,7 +2718,7 @@ impl IBluetooth for Bluetooth {
                     if UuidHelper::is_profile_supported(&p) {
                         match p {
                             Profile::Hid | Profile::Hogp => {
-                                self.hh.as_ref().unwrap().disconnect(&mut addr.unwrap());
+                                self.hh.as_ref().unwrap().disconnect(&mut addr.unwrap(), true);
                             }
 
                             Profile::A2dpSink
@@ -2889,7 +2889,7 @@ impl BtifHHCallbacks for Bluetooth {
                 "[{}]: Rejecting a unbonded device's attempt to connect to HID/HOG profiles",
                 DisplayAddress(&address)
             );
-            self.hh.as_ref().unwrap().disconnect(&mut address);
+            self.hh.as_ref().unwrap().disconnect(&mut address, true);
         }
     }
 
diff --git a/system/gd/rust/topshim/src/profiles/hid_host.rs b/system/gd/rust/topshim/src/profiles/hid_host.rs
index c77fa9b4754653351e2648e448bb3446f00ec8fa..d9d724b4cad78152083e336a5ce8a91d33af68a5 100644
--- a/system/gd/rust/topshim/src/profiles/hid_host.rs
+++ b/system/gd/rust/topshim/src/profiles/hid_host.rs
@@ -238,7 +238,7 @@ impl HidHost {
     #[profile_enabled_or(BtStatus::NotReady)]
     pub fn disconnect(&self, addr: &mut RawAddress) -> BtStatus {
         let addr_ptr = LTCheckedPtrMut::from_ref(addr);
-        BtStatus::from(ccall!(self, disconnect, addr_ptr.into()))
+        BtStatus::from(ccall!(self, disconnect, addr_ptr.into(), true))
     }
 
     #[profile_enabled_or(BtStatus::NotReady)]
diff --git a/system/gd/storage/config_keys.h b/system/gd/storage/config_keys.h
index d5e19d8794a749c0358b103adaaee5fbc4794f04..827badbc4650cdfaf7473e7fad1046b8bdcb4127 100644
--- a/system/gd/storage/config_keys.h
+++ b/system/gd/storage/config_keys.h
@@ -58,6 +58,7 @@
 #define BTIF_STORAGE_KEY_HID_DESCRIPTOR "HidDescriptor"
 #define BTIF_STORAGE_KEY_HID_DEVICE_CABLED "HidDeviceCabled"
 #define BTIF_STORAGE_KEY_HID_PRODUCT_ID "HidProductId"
+#define BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED "HidReConnectAllowed"
 #define BTIF_STORAGE_KEY_HID_REPORT "HidReport"
 #define BTIF_STORAGE_KEY_HID_REPORT_VERSION "HidReportVersion"
 #define BTIF_STORAGE_KEY_HID_SSR_MAX_LATENCY "HidSSRMaxLatency"
diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h
index c9ee0a95f1fbc2cd86bcc7d39ea6ecd610882a16..cc12e897411cabccced21df4988b935cdb7d6b0e 100644
--- a/system/include/hardware/bt_hh.h
+++ b/system/include/hardware/bt_hh.h
@@ -178,7 +178,7 @@ typedef struct {
   bt_status_t (*connect)(RawAddress* bd_addr);
 
   /** dis-connect from hid device */
-  bt_status_t (*disconnect)(RawAddress* bd_addr);
+  bt_status_t (*disconnect)(RawAddress* bd_addr, bool reconnect_allowed);
 
   /** Virtual UnPlug (VUP) the specified HID device */
   bt_status_t (*virtual_unplug)(RawAddress* bd_addr);