diff --git a/system/bta/csis/csis_client.cc b/system/bta/csis/csis_client.cc
index 187a1fcb309249a6dcf8928b46246b9546d963bf..a615c87d0220fc7839d00ef7a368b7fe50c2cf68 100644
--- a/system/bta/csis/csis_client.cc
+++ b/system/bta/csis/csis_client.cc
@@ -1281,7 +1281,7 @@ class CsisClientImpl : public CsisClient {
 
           instance->OnActiveScanResult(&p_data->inq_res);
         });
-    BTA_DmBleScan(enable, bluetooth::csis::kDefaultScanDurationS);
+    BTA_DmBleScan(enable, bluetooth::csis::kDefaultScanDurationS, true);
 
     /* Need to call it by ourselfs */
     if (!enable) {
diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc
index 61e022086714a3f6c2ca7ac7768fbf8215756add..a17058eb2165fca9408a26827ee51acc05789522 100644
--- a/system/bta/dm/bta_dm_act.cc
+++ b/system/bta/dm/bta_dm_act.cc
@@ -4016,9 +4016,11 @@ void bta_dm_ble_config_local_privacy(bool privacy_enable) {
   BTM_BleConfigPrivacy(privacy_enable);
 }
 
-static void bta_dm_start_scan(uint8_t duration_sec) {
-  tBTM_STATUS status = BTM_BleObserve(
-      true, duration_sec, bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb);
+static void bta_dm_start_scan(uint8_t duration_sec,
+                              bool low_latency_scan = false) {
+  tBTM_STATUS status =
+      BTM_BleObserve(true, duration_sec, bta_dm_observe_results_cb,
+                     bta_dm_observe_cmpl_cb, low_latency_scan);
 
   if (status != BTM_CMD_STARTED) {
     tBTA_DM_SEARCH data = {
@@ -4051,7 +4053,8 @@ void bta_dm_ble_observe(bool start, uint8_t duration,
   bta_dm_start_scan(duration);
 }
 
-void bta_dm_ble_scan(bool start, uint8_t duration_sec) {
+void bta_dm_ble_scan(bool start, uint8_t duration_sec,
+                     bool low_latency_scan = false) {
   /* Start or stop only if there is no active main scanner */
   if (bta_dm_search_cb.p_scan_cback != NULL) return;
 
@@ -4060,7 +4063,7 @@ void bta_dm_ble_scan(bool start, uint8_t duration_sec) {
     return;
   }
 
-  bta_dm_start_scan(duration_sec);
+  bta_dm_start_scan(duration_sec, low_latency_scan);
 }
 
 void bta_dm_ble_csis_observe(bool observe, tBTA_DM_SEARCH_CBACK* p_cback) {
diff --git a/system/bta/dm/bta_dm_api.cc b/system/bta/dm/bta_dm_api.cc
index 325d82ef75ba63e007a0285ace50d02a108ae8c2..72a99d47faeaba442eabe92c5cec7ecdc361d3c6 100644
--- a/system/bta/dm/bta_dm_api.cc
+++ b/system/bta/dm/bta_dm_api.cc
@@ -605,14 +605,16 @@ void BTA_DmBleObserve(bool start, uint8_t duration,
  * Parameters       start: start or stop the scan procedure,
  *                  duration_sec: Duration of the scan. Continuous scan if 0 is
  *                                passed,
+ *                  low_latency_scan: whether this is an low latency scan,
+ *                                    default is false.
  *
  * Returns          void
  *
  ******************************************************************************/
-void BTA_DmBleScan(bool start, uint8_t duration_sec) {
+void BTA_DmBleScan(bool start, uint8_t duration_sec, bool low_latency_scan) {
   APPL_TRACE_API("%s:start = %d ", __func__, start);
-  do_in_main_thread(FROM_HERE,
-                    base::Bind(bta_dm_ble_scan, start, duration_sec));
+  do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_scan, start, duration_sec,
+                                          low_latency_scan));
 }
 
 /*******************************************************************************
diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h
index 947d5ab5a7b695c39c0b0c6e62e1aef5af150f74..96f1f16ad0a1cb38de02916ea6ec30ec33f45f7c 100644
--- a/system/bta/dm/bta_dm_int.h
+++ b/system/bta/dm/bta_dm_int.h
@@ -538,7 +538,7 @@ void bta_dm_ble_set_conn_params(const RawAddress&, uint16_t, uint16_t, uint16_t,
                                 uint16_t);
 void bta_dm_close_gatt_conn(tBTA_DM_MSG* p_data);
 void bta_dm_ble_observe(bool, uint8_t, tBTA_DM_SEARCH_CBACK*);
-void bta_dm_ble_scan(bool, uint8_t);
+void bta_dm_ble_scan(bool, uint8_t, bool);
 void bta_dm_ble_csis_observe(bool, tBTA_DM_SEARCH_CBACK*);
 void bta_dm_ble_update_conn_params(const RawAddress&, uint16_t, uint16_t,
                                    uint16_t, uint16_t, uint16_t, uint16_t);
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index 97a574873161b46ccc55b149613ef04f7a5a5304..c395672f55f477542da47c772001e23825d9f0f9 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -1146,11 +1146,13 @@ void BTA_DmBleObserve(bool start, uint8_t duration,
  * Parameters       start: start or stop the scan procedure,
  *                  duration_sec: Duration of the scan. Continuous scan if 0 is
  *                                passed,
+ *                  low_latency_scan: whether this is a low latency scan,
+ *                                    default is false,
  *
  * Returns          void
  *
  ******************************************************************************/
-void BTA_DmBleScan(bool start, uint8_t duration);
+void BTA_DmBleScan(bool start, uint8_t duration, bool low_latency_scan = false);
 
 /*******************************************************************************
  *
diff --git a/system/bta/test/common/bta_dm_api_mock.cc b/system/bta/test/common/bta_dm_api_mock.cc
index 6a89920fee0f024c44a49ac4cdc846533025cb4c..e0c9941e3ff6eab6b11183bec3a9ea6dd7ea712f 100644
--- a/system/bta/test/common/bta_dm_api_mock.cc
+++ b/system/bta/test/common/bta_dm_api_mock.cc
@@ -23,9 +23,9 @@ void dm::SetMockBtaDmInterface(MockBtaDmInterface* mock_bta_dm_interface) {
   dm_interface = mock_bta_dm_interface;
 }
 
-void BTA_DmBleScan(bool start, uint8_t duration) {
+void BTA_DmBleScan(bool start, uint8_t duration, bool low_latency_scan) {
   LOG_ASSERT(dm_interface) << "Mock BTA DM interface not set!";
-  return dm_interface->BTA_DmBleScan(start, duration);
+  return dm_interface->BTA_DmBleScan(start, duration, low_latency_scan);
 }
 
 void BTA_DmBleCsisObserve(bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb) {
diff --git a/system/bta/test/common/bta_dm_api_mock.h b/system/bta/test/common/bta_dm_api_mock.h
index 9be98faaca2da501759351beebb41ce2d39410ec..9093bd3b296ca1ace2468cd8483e6d773bf2a725 100644
--- a/system/bta/test/common/bta_dm_api_mock.h
+++ b/system/bta/test/common/bta_dm_api_mock.h
@@ -26,7 +26,8 @@ namespace dm {
 
 class BtaDmInterface {
  public:
-  virtual void BTA_DmBleScan(bool start, uint8_t duration) = 0;
+  virtual void BTA_DmBleScan(bool start, uint8_t duration,
+                             bool low_latency_scan) = 0;
   virtual void BTA_DmBleCsisObserve(bool observe,
                                     tBTA_DM_SEARCH_CBACK* p_results_cb) = 0;
   virtual ~BtaDmInterface() = default;
@@ -34,7 +35,8 @@ class BtaDmInterface {
 
 class MockBtaDmInterface : public BtaDmInterface {
  public:
-  MOCK_METHOD((void), BTA_DmBleScan, (bool start, uint8_t duration));
+  MOCK_METHOD((void), BTA_DmBleScan,
+              (bool start, uint8_t duration, bool low_latency_scan));
   MOCK_METHOD((void), BTA_DmBleCsisObserve,
               (bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb));
 };
diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc
index 40440259a94e925a734a754619b04ae811661037..0f630763846f2ba0385c533506cd2b4ba8037570 100644
--- a/system/stack/btm/btm_ble_gap.cc
+++ b/system/stack/btm/btm_ble_gap.cc
@@ -492,13 +492,15 @@ void BTM_BleTargetAnnouncementObserve(bool enable,
  *                  duration: how long the scan should last, in seconds. 0 means
  *                  scan without timeout. Starting the scan second time without
  *                  timeout will disable the timer.
+ *                  low_latency_scan: whether this is a low latency scan,
+ *                                    default is false.
  *
  * Returns          void
  *
  ******************************************************************************/
 tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
                            tBTM_INQ_RESULTS_CB* p_results_cb,
-                           tBTM_CMPL_CB* p_cmpl_cb) {
+                           tBTM_CMPL_CB* p_cmpl_cb, bool low_latency_scan) {
   tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var;
   tBTM_STATUS status = BTM_WRONG_MODE;
 
@@ -507,13 +509,21 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
   uint32_t scan_window =
       !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
 
+  // use low latency scanning if the scanning is active
+  if (low_latency_scan) {
+    scan_interval = BTM_BLE_LOW_LATENCY_SCAN_INT;
+    scan_window = BTM_BLE_LOW_LATENCY_SCAN_WIN;
+  }
+
   BTM_TRACE_EVENT("%s : scan_type:%d, %d, %d", __func__, p_inq->scan_type,
-                  p_inq->scan_interval, p_inq->scan_window);
+                  scan_interval, scan_window);
 
   if (!controller_get_interface()->supports_ble()) return BTM_ILLEGAL_VALUE;
 
   if (start) {
-    /* shared inquiry database, do not allow observe if any inquiry is active */
+    /* shared inquiry database, do not allow observe if any inquiry is active.
+     * except we are doing CSIS active scanning
+     */
     if (btm_cb.ble_ctr_cb.is_ble_observe_active()) {
       if (duration == 0) {
         if (alarm_is_scheduled(btm_cb.ble_ctr_cb.observer_timer)) {
@@ -522,12 +532,26 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
           BTM_TRACE_ERROR("%s Scan with no duration started twice!", __func__);
         }
       } else {
-        if (alarm_is_scheduled(btm_cb.ble_ctr_cb.observer_timer)) {
+        if (!low_latency_scan &&
+            alarm_is_scheduled(btm_cb.ble_ctr_cb.observer_timer)) {
           BTM_TRACE_ERROR("%s Scan with duration started twice!", __func__);
         }
       }
-      BTM_TRACE_WARNING("%s Observer was already active", __func__);
-      return BTM_CMD_STARTED;
+      /*
+       * we stop current observation request for below scenarios
+       * 1. if the scan we wish to start is not low latency
+       * 2. current ongoing scanning is low latency
+       */
+      bool is_ongoing_low_latency =
+          p_inq->scan_interval == BTM_BLE_GAP_DISC_SCAN_INT &&
+          p_inq->scan_window == BTM_BLE_LOW_LATENCY_SCAN_WIN;
+      if (!low_latency_scan || is_ongoing_low_latency) {
+        BTM_TRACE_WARNING("%s Observer was already active, is_low_latency: %d",
+                          __func__, is_ongoing_low_latency);
+        return BTM_CMD_STARTED;
+      }
+      // stop any scan without low latency config
+      btm_ble_stop_observe();
     }
 
     btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb;
@@ -552,7 +576,10 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
         .start_time_ms = timestamper_in_milliseconds.GetTimestamp(),
         .results = 0,
     };
-    BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le observe started");
+
+    BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le observe started",
+                   base::StringPrintf("low latency scanning enabled: %d",
+                                      low_latency_scan));
 
     if (status == BTM_CMD_STARTED) {
       btm_cb.ble_ctr_cb.set_ble_observe_active();
diff --git a/system/stack/include/btm_ble_api.h b/system/stack/include/btm_ble_api.h
index dadfdaf64172993f587a5146e4ea6157027bf621..d204dc2582b17ac8ae51a36a19810fdd3c2129b4 100644
--- a/system/stack/include/btm_ble_api.h
+++ b/system/stack/include/btm_ble_api.h
@@ -165,13 +165,16 @@ void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback,
  *                  duration: how long the scan should last, in seconds. 0 means
  *                  scan without timeout. Starting the scan second time without
  *                  timeout will disable the timer.
+ *                  low_latency_scan: whether this is a low latency scan,
+ *                                    default is false.
  *
  * Returns          void
  *
  ******************************************************************************/
 tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
                            tBTM_INQ_RESULTS_CB* p_results_cb,
-                           tBTM_CMPL_CB* p_cmpl_cb);
+                           tBTM_CMPL_CB* p_cmpl_cb,
+                           bool low_latency_scan = false);
 
 /*******************************************************************************
  *
diff --git a/system/stack/include/btm_client_interface.h b/system/stack/include/btm_client_interface.h
index ca333dfe7db6960448910eb9c14480609cd4f691..24669beef29b7a48744b84fbe8171c9ac04645bc 100644
--- a/system/stack/include/btm_client_interface.h
+++ b/system/stack/include/btm_client_interface.h
@@ -166,7 +166,8 @@ struct btm_client_interface_t {
     tBTM_STATUS (*BTM_BleGetEnergyInfo)(tBTM_BLE_ENERGY_INFO_CBACK* callback);
     tBTM_STATUS (*BTM_BleObserve)(bool start, uint8_t duration,
                                   tBTM_INQ_RESULTS_CB* p_results_cb,
-                                  tBTM_CMPL_CB* p_cmpl_cb);
+                                  tBTM_CMPL_CB* p_cmpl_cb,
+                                  bool low_latency_scan);
     tBTM_STATUS (*BTM_SetBleDataLength)(const RawAddress& bd_addr,
                                         uint16_t tx_pdu_length);
     void (*BTM_BleConfirmReply)(const RawAddress& bd_addr, uint8_t res);
diff --git a/system/test/mock/mock_bta_dm_api.cc b/system/test/mock/mock_bta_dm_api.cc
index c61070b715913bcb875cf537a2d648c5abe2195d..8b54c5896270cc0b0c236c6cc7eb6f3c3a033254 100644
--- a/system/test/mock/mock_bta_dm_api.cc
+++ b/system/test/mock/mock_bta_dm_api.cc
@@ -123,9 +123,9 @@ void BTA_DmBleRequestMaxTxDataLength(const RawAddress& remote_device) {
   inc_func_call_count(__func__);
   test::mock::bta_dm_api::BTA_DmBleRequestMaxTxDataLength(remote_device);
 }
-void BTA_DmBleScan(bool start, uint8_t duration) {
+void BTA_DmBleScan(bool start, uint8_t duration, bool low_latency_scan) {
   inc_func_call_count(__func__);
-  test::mock::bta_dm_api::BTA_DmBleScan(start, duration);
+  test::mock::bta_dm_api::BTA_DmBleScan(start, duration, low_latency_scan);
 }
 void BTA_DmBleSecurityGrant(const RawAddress& bd_addr,
                             tBTA_DM_BLE_SEC_GRANT res) {
diff --git a/system/test/mock/mock_bta_dm_api.h b/system/test/mock/mock_bta_dm_api.h
index cd3473ee745da7ed47a5b0d30633e158d755beb8..1be9353e0253169ab0a19dea76bc102a4391de8e 100644
--- a/system/test/mock/mock_bta_dm_api.h
+++ b/system/test/mock/mock_bta_dm_api.h
@@ -186,12 +186,14 @@ struct BTA_DmBleRequestMaxTxDataLength {
 extern struct BTA_DmBleRequestMaxTxDataLength BTA_DmBleRequestMaxTxDataLength;
 
 // Name: BTA_DmBleScan
-// Params: bool start, uint8_t duration
+// Params: bool start, uint8_t duration, bool low_latency_scan
 // Return: void
 struct BTA_DmBleScan {
-  std::function<void(bool start, uint8_t duration)> body{
-      [](bool start, uint8_t duration) {}};
-  void operator()(bool start, uint8_t duration) { body(start, duration); };
+  std::function<void(bool start, uint8_t duration, bool low_latency_scan)> body{
+      [](bool start, uint8_t duration, bool low_latency_scan) {}};
+  void operator()(bool start, uint8_t duration, bool low_latency_scan) {
+    body(start, duration, low_latency_scan);
+  };
 };
 extern struct BTA_DmBleScan BTA_DmBleScan;
 
diff --git a/system/test/mock/mock_stack_btm.cc b/system/test/mock/mock_stack_btm.cc
index 90a8669d1d9596dd4d2ef04d0c28007e67cb8c43..475a45780c79422c803931b1e638477b1442f1d2 100644
--- a/system/test/mock/mock_stack_btm.cc
+++ b/system/test/mock/mock_stack_btm.cc
@@ -203,7 +203,8 @@ struct btm_client_interface_t btm_client_interface = {
                                    tBTM_BLE_LOCAL_KEYS* p_key) {},
         .BTM_BleObserve =
             [](bool start, uint8_t duration, tBTM_INQ_RESULTS_CB* p_results_cb,
-               tBTM_CMPL_CB* p_cmpl_cb) -> tBTM_STATUS { return BTM_SUCCESS; },
+               tBTM_CMPL_CB* p_cmpl_cb,
+               bool low_latency_scan) -> tBTM_STATUS { return BTM_SUCCESS; },
         .BTM_BlePasskeyReply = [](const RawAddress& bd_addr, uint8_t res,
                                   uint32_t passkey) {},
         .BTM_BleReadControllerFeatures =
diff --git a/system/test/mock/mock_stack_btm_ble_gap.cc b/system/test/mock/mock_stack_btm_ble_gap.cc
index a69a0e642d863fd5a7a6dd92a982b4fd119a308b..82c99df7bb1dc4df67dc6bdf5ef98cd3c88ca31b 100644
--- a/system/test/mock/mock_stack_btm_ble_gap.cc
+++ b/system/test/mock/mock_stack_btm_ble_gap.cc
@@ -90,7 +90,7 @@ bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) {
 }
 tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
                            tBTM_INQ_RESULTS_CB* p_results_cb,
-                           tBTM_CMPL_CB* p_cmpl_cb) {
+                           tBTM_CMPL_CB* p_cmpl_cb, bool low_latency_scan) {
   inc_func_call_count(__func__);
   return BTM_SUCCESS;
 }