diff --git a/floss/hcidoc/src/groups/connections.rs b/floss/hcidoc/src/groups/connections.rs
index 7d600b3191521231cf52916f10c7af52ed614d2c..13a398c91901476449d3f5f6bea4cb1da8fa8d6a 100644
--- a/floss/hcidoc/src/groups/connections.rs
+++ b/floss/hcidoc/src/groups/connections.rs
@@ -7,16 +7,17 @@ use std::io::Write;
 use crate::engine::{Rule, RuleGroup, Signal};
 use crate::parser::{Packet, PacketChild};
 use bt_packets::hci::{
-    Acl, AclCommandChild, Address, CommandChild, CommandStatus, ConnectionManagementCommandChild,
-    DisconnectReason, ErrorCode, Event, EventChild, LeConnectionManagementCommandChild,
-    LeMetaEventChild, NumberOfCompletedPackets, OpCode, ScoConnectionCommandChild,
-    SecurityCommandChild, SubeventCode,
+    Acl, AclCommandChild, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, CommandStatus,
+    ConnectionManagementCommandChild, DisconnectReason, ErrorCode, Event, EventChild,
+    LeConnectionManagementCommandChild, LeMetaEventChild, NumberOfCompletedPackets, OpCode,
+    ScoConnectionCommandChild, SecurityCommandChild, SubeventCode,
 };
 
 enum ConnectionSignal {
     LinkKeyMismatch, // Peer forgets the link key or it mismatches ours
     NocpDisconnect,  // Peer is disconnected when NOCP packet isn't yet received
     NocpTimeout,     // Host doesn't receive NOCP packet 5 seconds after ACL is sent
+    ApteDisconnect,  // Host doesn't receive a packet with valid MIC for a while.
 }
 
 impl Into<&'static str> for ConnectionSignal {
@@ -25,6 +26,7 @@ impl Into<&'static str> for ConnectionSignal {
             ConnectionSignal::LinkKeyMismatch => "LinkKeyMismatch",
             ConnectionSignal::NocpDisconnect => "Nocp",
             ConnectionSignal::NocpTimeout => "Nocp",
+            ConnectionSignal::ApteDisconnect => "AuthenticatedPayloadTimeoutExpired",
         }
     }
 }
@@ -73,6 +75,9 @@ struct OddDisconnectionsRule {
     /// identify bursts.
     nocp_by_handle: HashMap<ConnectionHandle, NocpData>,
 
+    /// Number of |Authenticated Payload Timeout Expired| events hapened.
+    apte_by_handle: HashMap<ConnectionHandle, u32>,
+
     /// Pre-defined signals discovered in the logs.
     signals: Vec<Signal>,
 
@@ -91,6 +96,7 @@ impl OddDisconnectionsRule {
             sco_connection_attempt: HashMap::new(),
             last_sco_connection_attempt: None,
             nocp_by_handle: HashMap::new(),
+            apte_by_handle: HashMap::new(),
             signals: vec![],
             reportable: vec![],
         }
@@ -315,6 +321,26 @@ impl OddDisconnectionsRule {
 
                 // Remove nocp information for handles that were removed.
                 self.nocp_by_handle.remove(&handle);
+
+                // Check if auth payload timeout happened.
+                match self.apte_by_handle.get_mut(&handle) {
+                    Some(apte_count) => {
+                        self.signals.push(Signal {
+                            index: packet.index,
+                            ts: packet.ts.clone(),
+                            tag: ConnectionSignal::ApteDisconnect.into(),
+                        });
+
+                        self.reportable.push((
+                            packet.ts,
+                            format!("DisconnectionComplete with {} Authenticated Payload Timeout Expired (handle={})",
+                            apte_count, handle)));
+                    }
+                    None => (),
+                }
+
+                // Remove apte information for handles that were removed.
+                self.apte_by_handle.remove(&handle);
             }
 
             EventChild::SynchronousConnectionComplete(scc) => {
@@ -436,6 +462,11 @@ impl OddDisconnectionsRule {
         }
     }
 
+    fn process_apte(&mut self, apte: &AuthenticatedPayloadTimeoutExpired, _packet: &Packet) {
+        let handle = apte.get_connection_handle();
+        *self.apte_by_handle.entry(handle).or_insert(0) += 1;
+    }
+
     fn process_reset(&mut self) {
         self.active_handles.clear();
         self.connection_attempt.clear();
@@ -445,6 +476,7 @@ impl OddDisconnectionsRule {
         self.sco_connection_attempt.clear();
         self.last_sco_connection_attempt = None;
         self.nocp_by_handle.clear();
+        self.apte_by_handle.clear();
     }
 }
 
@@ -518,6 +550,10 @@ impl Rule for OddDisconnectionsRule {
                     self.process_nocp(&nocp, packet);
                 }
 
+                EventChild::AuthenticatedPayloadTimeoutExpired(apte) => {
+                    self.process_apte(&apte, packet);
+                }
+
                 // end hci event
                 _ => (),
             },
diff --git a/system/main/shim/hci_layer.cc b/system/main/shim/hci_layer.cc
index 424c21de5ff56034bb4568531a3230a7c94384ee..d3ed495ce36424872f61434289a8cfea5eb57ae5 100644
--- a/system/main/shim/hci_layer.cc
+++ b/system/main/shim/hci_layer.cc
@@ -113,6 +113,7 @@ bool is_valid_event_code(bluetooth::hci::EventCode event_code) {
       return true;
     case bluetooth::hci::EventCode::VENDOR_SPECIFIC:
     case bluetooth::hci::EventCode::LE_META_EVENT:  // Private to hci
+    case bluetooth::hci::EventCode::AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED:
       return false;
   }
   return false;
diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl
index f75bbe58d8c9bd3c4c3efd53eaa761cb5a02612b..d4b278bddb15902d31c18b397aa65b9939cfa317 100644
--- a/system/pdl/hci/hci_packets.pdl
+++ b/system/pdl/hci/hci_packets.pdl
@@ -831,6 +831,7 @@ enum EventCode : 8 {
   REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D,
   LE_META_EVENT = 0x3e,
   NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48,
+  AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED = 0x57,
   VENDOR_SPECIFIC = 0xFF,
 }
 
@@ -5803,6 +5804,11 @@ packet NumberOfCompletedDataBlocks : Event (event_code = NUMBER_OF_COMPLETED_DAT
   _payload_, // placeholder (unimplemented)
 }
 
+packet AuthenticatedPayloadTimeoutExpired : Event (event_code = AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED) {
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
 // LE Events
 packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) {
   status : ErrorCode,