diff --git a/system/gd/rust/linux/mgmt/Cargo.toml b/system/gd/rust/linux/mgmt/Cargo.toml
index 042b25b00177e91392908e2d1464d20ec92798c6..ca38dd178ff88a49c14da84c8321f49f5da5da60 100644
--- a/system/gd/rust/linux/mgmt/Cargo.toml
+++ b/system/gd/rust/linux/mgmt/Cargo.toml
@@ -32,6 +32,7 @@ regex = "1.5"
 serde_json = "1.0"
 syslog = "6"
 tokio = { version = "1.0", features = ["fs", "macros", "rt-multi-thread", "sync"] }
+libc = "0.2"
 
 [build-dependencies]
 pkg-config = "0.3.19"
diff --git a/system/gd/rust/linux/mgmt/src/state_machine.rs b/system/gd/rust/linux/mgmt/src/state_machine.rs
index 8647c68e8df66c5fa94e43298931454083cf1086..e9de581723a16e6562a348a31a0704b271136e4f 100644
--- a/system/gd/rust/linux/mgmt/src/state_machine.rs
+++ b/system/gd/rust/linux/mgmt/src/state_machine.rs
@@ -5,6 +5,7 @@ use bt_utils::socket::{
     BtSocket, HciChannels, MgmtCommand, MgmtCommandResponse, MgmtEvent, HCI_DEV_NONE,
 };
 
+use libc;
 use log::{debug, error, info, warn};
 use nix::sys::signal::{self, Signal};
 use nix::unistd::Pid;
@@ -36,6 +37,10 @@ pub const INDEX_REMOVED_DEBOUNCE_TIME: Duration = Duration::from_millis(150);
 /// to avoid dead process + PID not cleaned up from happening.
 pub const PID_RUNNING_CHECK_PERIOD: Duration = Duration::from_secs(60);
 
+const HCI_BIND_MAX_RETRY: i32 = 2;
+
+const HCI_BIND_RETRY_INTERVAL: Duration = Duration::from_millis(10);
+
 #[derive(Debug, PartialEq, Copy, Clone)]
 #[repr(u32)]
 pub enum ProcessState {
@@ -362,19 +367,37 @@ fn configure_hci(hci_tx: mpsc::Sender<Message>) {
         x => debug!("Socket open at fd: {}", x),
     }
 
-    // Bind to control channel (which is used for mgmt commands). We provide
-    // HCI_DEV_NONE because we don't actually need a valid HCI dev for some MGMT commands.
-    match btsock.bind_channel(HciChannels::Control, HCI_DEV_NONE) {
-        -1 => {
-            panic!(
-                "Failed to bind control channel with errno={}",
-                std::io::Error::last_os_error().raw_os_error().unwrap_or(0)
-            );
+    tokio::spawn(async move {
+        // Bind to control channel (which is used for mgmt commands). We provide
+        // HCI_DEV_NONE because we don't actually need a valid HCI dev for some MGMT commands.
+        let mut bind_succ = false;
+        for _i in 0..HCI_BIND_MAX_RETRY {
+            match btsock.bind_channel(HciChannels::Control, HCI_DEV_NONE) {
+                -1 => {
+                    match std::io::Error::last_os_error().raw_os_error().unwrap_or(0) {
+                        libc::EINVAL => {
+                            // If MGMT hasn't been initialized EINVAL will be returned.
+                            // Just wait for a short time and try again.
+                            debug!("Got EINVAL in bind. Wait and try again");
+                            tokio::time::sleep(HCI_BIND_RETRY_INTERVAL).await;
+                            continue;
+                        }
+                        others => {
+                            panic!("Failed to bind control channel with errno={}", others);
+                        }
+                    }
+                }
+                _ => {
+                    bind_succ = true;
+                    break;
+                }
+            };
+        }
+
+        if !bind_succ {
+            panic!("bind failed too many times!!");
         }
-        _ => (),
-    };
 
-    tokio::spawn(async move {
         debug!("Spawned hci notify task");
 
         // Make this into an AsyncFD and start using it for IO