diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc
index a021ffd1e57a91d89e10918a689829a7209c4667..6d9d986bf3a7ab027e4dc44f8451c41d1dfa246a 100644
--- a/system/bta/dm/bta_dm_act.cc
+++ b/system/bta/dm/bta_dm_act.cc
@@ -59,6 +59,7 @@
 #include "stack/include/bt_types.h"
 #include "stack/include/btm_client_interface.h"
 #include "stack/include/btu.h"  // do_in_main_thread
+#include "stack/include/srvc_api.h"  // DIS_ReadDISInfo
 #include "types/bluetooth/uuid.h"
 #include "types/raw_address.h"
 
@@ -1198,6 +1199,21 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
         }
       } while (p_sdp_rec);
     }
+
+#if TARGET_FLOSS
+    tSDP_DI_GET_RECORD di_record;
+    if (SDP_GetDiRecord(1, &di_record, bta_dm_search_cb.p_sdp_db) ==
+        SDP_SUCCESS) {
+      tBTA_DM_SEARCH result;
+      result.did_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
+      result.did_res.vendor_id_src = di_record.rec.vendor_id_source;
+      result.did_res.vendor_id = di_record.rec.vendor;
+      result.did_res.product_id = di_record.rec.product;
+      result.did_res.version = di_record.rec.version;
+      bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result);
+    }
+#endif
+
     /* if there are more services to search for */
     if (bta_dm_search_cb.services_to_search) {
       /* Free up the p_sdp_db before checking the next one */
@@ -1293,6 +1309,26 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
   }
 }
 
+/** Callback of peer's DIS reply. This is only called for floss */
+#if TARGET_FLOSS
+static void bta_dm_read_dis_cmpl(const RawAddress& addr,
+                                 tDIS_VALUE* p_dis_value) {
+  if (!p_dis_value) {
+    LOG_WARN("read DIS failed");
+  } else {
+    tBTA_DM_SEARCH result;
+    result.did_res.bd_addr = addr;
+    result.did_res.vendor_id_src = p_dis_value->pnp_id.vendor_id_src;
+    result.did_res.vendor_id = p_dis_value->pnp_id.vendor_id;
+    result.did_res.product_id = p_dis_value->pnp_id.product_id;
+    result.did_res.version = p_dis_value->pnp_id.product_version;
+    bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result);
+  }
+
+  bta_dm_execute_queued_request();
+}
+#endif
+
 /*******************************************************************************
  *
  * Function         bta_dm_search_cmpl
@@ -1347,6 +1383,13 @@ void bta_dm_search_cmpl() {
 
   bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);
 
+#if TARGET_FLOSS
+  if (DIS_ReadDISInfo(bta_dm_search_cb.peer_bdaddr, bta_dm_read_dis_cmpl,
+                      DIS_ATTR_PNP_ID_BIT)) {
+    return;
+  }
+#endif
+
   bta_dm_execute_queued_request();
 }
 
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index de1cc993cfeac0422217a7cf41a5187fdd774722..0c433e335117ae99820654b868416101d439b69f 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -423,6 +423,7 @@ typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data);
   3 /* Discovery result for BLE GATT based servoce on a peer device. */
 #define BTA_DM_DISC_CMPL_EVT 4          /* Discovery complete. */
 #define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */
+#define BTA_DM_DID_RES_EVT 7            /* Vendor/Product ID search result */
 
 typedef uint8_t tBTA_DM_SEARCH_EVT;
 
@@ -477,6 +478,15 @@ typedef struct {
       services; /* GATT based Services UUID found on peer device. */
 } tBTA_DM_DISC_BLE_RES;
 
+/* Structure associated with tBTA_DM_DID_RES */
+typedef struct {
+  RawAddress bd_addr; /* BD address peer device. */
+  uint8_t vendor_id_src;
+  uint16_t vendor_id;
+  uint16_t product_id;
+  uint16_t version;
+} tBTA_DM_DID_RES;
+
 /* Union of all search callback structures */
 typedef union {
   tBTA_DM_INQ_RES inq_res;   /* Inquiry result for a peer device. */
@@ -484,6 +494,7 @@ typedef union {
   tBTA_DM_DISC_RES disc_res; /* Discovery result for a peer device. */
   tBTA_DM_DISC_BLE_RES
       disc_ble_res;             /* discovery result for GATT based service */
+  tBTA_DM_DID_RES did_res;      /* Vendor and Product ID of peer device */
 } tBTA_DM_SEARCH;
 
 /* Search callback */
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index c2c7b089a5ae39eda27902a1fbd30b2f819854ed..03910f668c59b0dca76408e696ce6eb51857290b 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -1630,6 +1630,29 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event,
                                          num_properties, prop);
     } break;
 
+    case BTA_DM_DID_RES_EVT: {
+      bt_property_t prop_did;
+      RawAddress& bd_addr = p_data->did_res.bd_addr;
+      bt_vendor_product_info_t vp_info;
+
+      vp_info.vendor_id_src = p_data->did_res.vendor_id_src;
+      vp_info.vendor_id = p_data->did_res.vendor_id;
+      vp_info.product_id = p_data->did_res.product_id;
+      vp_info.version = p_data->did_res.version;
+
+      prop_did.type = BT_PROPERTY_VENDOR_PRODUCT_INFO;
+      prop_did.val = &vp_info;
+      prop_did.len = sizeof(vp_info);
+
+      bt_status_t ret =
+          btif_storage_set_remote_device_property(&bd_addr, &prop_did);
+      ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+
+      /* Send the event to the BTIF */
+      invoke_remote_device_properties_cb(BT_STATUS_SUCCESS, bd_addr, 1,
+                                         &prop_did);
+    } break;
+
     default: { ASSERTC(0, "unhandled search services event", event); } break;
   }
 }
diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc
index df007ead8f2d96d83403f2d925086185fc638a4e..0ed4bba8b6065f26e08f77e69093995f93803f5b 100644
--- a/system/btif/src/btif_storage.cc
+++ b/system/btif/src/btif_storage.cc
@@ -102,6 +102,11 @@ using bluetooth::groups::DeviceGroups;
 #define BTIF_STORAGE_CSIS_SET_INFO_BIN "CsisSetInfoBin"
 #define BTIF_STORAGE_LEAUDIO_AUTOCONNECT "LeAudioAutoconnect"
 
+#define BTIF_STORAGE_PATH_VENDOR_ID_SOURCE "VendorIdSource"
+#define BTIF_STORAGE_PATH_VENDOR_ID "VendorId"
+#define BTIF_STORAGE_PATH_PRODUCT_ID "ProductId"
+#define BTIF_STORAGE_PATH_VERSION "ProductVersion"
+
 /* This is a local property to add a device found */
 #define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
 
@@ -286,6 +291,17 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) {
       int val = *(uint16_t*)prop->val;
       btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_APPEARANCE, val);
     } break;
+    case BT_PROPERTY_VENDOR_PRODUCT_INFO: {
+      bt_vendor_product_info_t* info = (bt_vendor_product_info_t*)prop->val;
+      if (!info) return false;
+
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID_SOURCE,
+                          info->vendor_id_src);
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID, info->vendor_id);
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_PRODUCT_ID,
+                          info->product_id);
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VERSION, info->version);
+    } break;
 
     default:
       BTIF_TRACE_ERROR("Unknown prop type:%d", prop->type);
@@ -422,6 +438,30 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) {
       }
     } break;
 
+    case BT_PROPERTY_VENDOR_PRODUCT_INFO: {
+      bt_vendor_product_info_t* info = (bt_vendor_product_info_t*)prop->val;
+      int val;
+
+      if (prop->len >= (int)sizeof(bt_vendor_product_info_t)) {
+        ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID_SOURCE,
+                                  &val);
+        info->vendor_id_src = (uint8_t)val;
+
+        if (ret) {
+          ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID, &val);
+          info->vendor_id = (uint16_t)val;
+        }
+        if (ret) {
+          ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_PRODUCT_ID, &val);
+          info->product_id = (uint16_t)val;
+        }
+        if (ret) {
+          ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_VERSION, &val);
+          info->version = (uint16_t)val;
+        }
+      }
+    } break;
+
     default:
       BTIF_TRACE_ERROR("Unknow prop type:%d", prop->type);
       return false;
@@ -1036,7 +1076,7 @@ bt_status_t btif_storage_load_bonded_devices(void) {
   uint32_t i = 0;
   bt_property_t adapter_props[6];
   uint32_t num_props = 0;
-  bt_property_t remote_properties[8];
+  bt_property_t remote_properties[9];
   RawAddress addr;
   bt_bdname_t name, alias;
   bt_scan_mode_t mode;
@@ -1154,6 +1194,15 @@ bt_status_t btif_storage_load_bonded_devices(void) {
                                    remote_properties[num_props]);
       num_props++;
 
+#if TARGET_FLOSS
+      // Floss needs VID:PID for metrics purposes
+      bt_vendor_product_info_t vp_info;
+      BTIF_STORAGE_GET_REMOTE_PROP(
+          p_remote_addr, BT_PROPERTY_VENDOR_PRODUCT_INFO, &vp_info,
+          sizeof(vp_info), remote_properties[num_props]);
+      num_props++;
+#endif
+
       btif_remote_properties_evt(BT_STATUS_SUCCESS, p_remote_addr, num_props,
                                  remote_properties);
     }
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index 74726d1d5aea0acd6a05824b76d82f4554ca6f8f..98d38fbeb94ceaaf7022ffe12be9bf39110dfa7c 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -214,6 +214,14 @@ typedef struct {
   bool le_periodic_advertising_sync_transfer_recipient_supported;
 } bt_local_le_features_t;
 
+/** Bluetooth Vendor and Product ID info */
+typedef struct {
+  uint8_t vendor_id_src;
+  uint16_t vendor_id;
+  uint16_t product_id;
+  uint16_t version;
+} bt_vendor_product_info_t;
+
 /* Stored the default/maximum/minimum buffer time for dynamic audio buffer.
  * For A2DP offload usage, the unit is millisecond.
  * For A2DP legacy usage, the unit is buffer queue size*/
@@ -347,6 +355,13 @@ typedef enum {
    */
   BT_PROPERTY_APPEARANCE,
 
+  /**
+   * Description - Peer devices' vendor and product ID.
+   * Access mode - GET.
+   * Data Type - bt_vendor_product_info_t.
+   */
+  BT_PROPERTY_VENDOR_PRODUCT_INFO,
+
   BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
 } bt_property_type_t;