diff --git a/system/gd/rust/linux/dbus_projection/Cargo.toml b/system/gd/rust/linux/dbus_projection/Cargo.toml
index 166d9288af58b17375b366eadd9c4de161ed1eeb..3cac0d889ccbfb6366dbcd986752fa54a97cb9c1 100644
--- a/system/gd/rust/linux/dbus_projection/Cargo.toml
+++ b/system/gd/rust/linux/dbus_projection/Cargo.toml
@@ -4,4 +4,6 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
+dbus_macros = { path = "dbus_macros" }
 dbus = "0.9.2"
+dbus-tokio = "0.7.3"
diff --git a/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml b/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml
index 84585d8d4c264e4168e768ba30d9c15410510170..997a11b354023c535b6f84ca8ac3c92268877c54 100644
--- a/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml
+++ b/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml
@@ -7,6 +7,6 @@ edition = "2018"
 proc-macro = true
 
 [dependencies]
-syn = "1.0"
+syn = { version = "1.0.58", features = ['default', 'full'] }
 quote = "1.0"
 proc-macro2 = "1.0"
diff --git a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
index 9f06c5aa824ca69ce7db0000cd366356f6961e7f..aa4399ed302673793358763de0bce8c5c98ff7cd 100644
--- a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
+++ b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
@@ -183,13 +183,13 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
 
         pub fn #fn_ident<T: 'static + #api_iface_ident + Send + ?Sized, P: Into<dbus::Path<'static>>>(
             path: P,
-            conn: std::sync::Arc<SyncConnection>,
+            conn: std::sync::Arc<dbus::nonblock::SyncConnection>,
             cr: &mut dbus_crossroads::Crossroads,
             obj: #obj_type,
             disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
         ) {
             fn get_iface_token<T: #api_iface_ident + Send + ?Sized>(
-                conn: std::sync::Arc<SyncConnection>,
+                conn: std::sync::Arc<dbus::nonblock::SyncConnection>,
                 cr: &mut dbus_crossroads::Crossroads,
                 disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
             ) -> dbus_crossroads::IfaceToken<#obj_type> {
@@ -314,7 +314,7 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream {
 
             fn from_dbus(
                 data__: dbus::arg::PropMap,
-                conn__: Option<std::sync::Arc<SyncConnection>>,
+                conn__: Option<std::sync::Arc<dbus::nonblock::SyncConnection>>,
                 remote__: Option<dbus::strings::BusName<'static>>,
                 disconnect_watcher__: Option<std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>>,
             ) -> Result<#struct_ident, Box<dyn std::error::Error>> {
@@ -440,7 +440,7 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {
         }
 
         struct #struct_ident {
-            conn: std::sync::Arc<SyncConnection>,
+            conn: std::sync::Arc<dbus::nonblock::SyncConnection>,
             remote: dbus::strings::BusName<'static>,
             objpath: Path<'static>,
             disconnect_watcher: std::sync::Arc<std::sync::Mutex<DisconnectWatcher>>,
@@ -465,7 +465,7 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {
 
             fn from_dbus(
                 objpath__: Path<'static>,
-                conn__: Option<std::sync::Arc<SyncConnection>>,
+                conn__: Option<std::sync::Arc<dbus::nonblock::SyncConnection>>,
                 remote__: Option<dbus::strings::BusName<'static>>,
                 disconnect_watcher__: Option<std::sync::Arc<std::sync::Mutex<DisconnectWatcher>>>,
             ) -> Result<Box<dyn #trait_ + Send>, Box<dyn std::error::Error>> {
@@ -559,10 +559,18 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream {
             type RustType = dbus::arg::PropMap;
             fn ref_arg_to_rust(
                 arg: &(dyn dbus::arg::RefArg + 'static),
-                _name: String,
+                name: String,
             ) -> Result<Self::RustType, Box<dyn Error>> {
                 let mut map: dbus::arg::PropMap = std::collections::HashMap::new();
-                let mut iter = arg.as_iter().unwrap();
+                let mut iter = match arg.as_iter() {
+                    None => {
+                        return Err(Box::new(DBusArgError::new(String::from(format!(
+                            "{} is not iterable",
+                            name,
+                        )))))
+                    }
+                    Some(item) => item,
+                };
                 let mut key = iter.next();
                 let mut val = iter.next();
                 while !key.is_none() && !val.is_none() {
@@ -602,7 +610,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream {
 
             fn from_dbus(
                 x: Self::DBusType,
-                conn: Option<Arc<SyncConnection>>,
+                conn: Option<Arc<dbus::nonblock::SyncConnection>>,
                 remote: Option<BusName<'static>>,
                 disconnect_watcher: Option<Arc<Mutex<DisconnectWatcher>>>,
             ) -> Result<Self, Box<dyn Error>>
@@ -627,7 +635,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream {
 
             fn from_dbus(
                 data: T,
-                _conn: Option<Arc<SyncConnection>>,
+                _conn: Option<Arc<dbus::nonblock::SyncConnection>>,
                 _remote: Option<BusName<'static>>,
                 _disconnect_watcher: Option<Arc<Mutex<DisconnectWatcher>>>,
             ) -> Result<T, Box<dyn Error>> {
@@ -644,7 +652,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream {
 
             fn from_dbus(
                 data: Vec<T::DBusType>,
-                conn: Option<Arc<SyncConnection>>,
+                conn: Option<Arc<dbus::nonblock::SyncConnection>>,
                 remote: Option<BusName<'static>>,
                 disconnect_watcher: Option<Arc<Mutex<DisconnectWatcher>>>,
             ) -> Result<Vec<T>, Box<dyn Error>> {
diff --git a/system/gd/rust/linux/dbus_projection/tests/conversions.rs b/system/gd/rust/linux/dbus_projection/tests/conversions.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ab57d71947be38d35ed34c624cb10a095276b33c
--- /dev/null
+++ b/system/gd/rust/linux/dbus_projection/tests/conversions.rs
@@ -0,0 +1,176 @@
+use core::any::Any;
+
+use dbus_macros::{dbus_propmap, generate_dbus_arg};
+
+use dbus::arg::{Arg, ArgType, IterAppend, RefArg};
+use dbus::Signature;
+
+generate_dbus_arg!();
+
+#[derive(Debug, Default, Clone, PartialEq)]
+struct OtherStruct {
+    address: String,
+}
+
+#[dbus_propmap(OtherStruct)]
+struct OtherStructDBus {
+    address: String,
+}
+
+#[derive(Debug, Default, Clone, PartialEq)]
+struct SomeStruct {
+    name: String,
+    number: i32,
+    other_struct: OtherStruct,
+    bytes: Vec<u8>,
+    nested: Vec<Vec<String>>,
+    recursive: Vec<SomeStruct>,
+}
+
+#[dbus_propmap(SomeStruct)]
+struct SomeStructDBus {
+    name: String,
+    number: i32,
+    other_struct: OtherStruct,
+    bytes: Vec<u8>,
+    nested: Vec<Vec<String>>,
+    recursive: Vec<SomeStruct>,
+}
+
+// Pretends to be a D-Bus dictionary.
+#[derive(Debug)]
+struct FakeDictionary {
+    items: Vec<(String, Box<dyn RefArg>)>,
+}
+
+impl RefArg for FakeDictionary {
+    fn arg_type(&self) -> ArgType {
+        todo!()
+    }
+    fn signature(&self) -> dbus::Signature<'static> {
+        todo!()
+    }
+    fn append(&self, _: &mut IterAppend<'_>) {
+        todo!()
+    }
+    fn as_any(&self) -> &(dyn Any + 'static) {
+        todo!()
+    }
+    fn as_any_mut(&mut self) -> &mut (dyn Any + 'static) {
+        todo!()
+    }
+    fn box_clone(&self) -> Box<dyn RefArg + 'static> {
+        Box::new(FakeDictionary {
+            items: self.items.iter().map(|(k, v)| (k.clone(), v.box_clone())).collect(),
+        })
+    }
+
+    fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item = &'b dyn RefArg> + 'b>> {
+        Some(Box::new(
+            self.items
+                .iter()
+                .flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()),
+        ))
+    }
+}
+
+impl Arg for FakeDictionary {
+    const ARG_TYPE: ArgType = ArgType::Array;
+    fn signature() -> dbus::Signature<'static> {
+        Signature::from("a{sv}")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_dbus_propmap_error() {
+        let data_dbus = String::from("some data");
+        let result = <dbus::arg::PropMap as RefArgToRust>::ref_arg_to_rust(
+            &data_dbus,
+            String::from("Some Variable"),
+        );
+        assert!(result.is_err());
+        assert_eq!("Some Variable is not iterable", result.unwrap_err().to_string());
+    }
+
+    #[test]
+    fn test_dbus_propmap_success() {
+        let data_dbus = FakeDictionary {
+            items: vec![
+                (String::from("name"), Box::new(String::from("foo"))),
+                (String::from("number"), Box::new(100)),
+                (
+                    String::from("other_struct"),
+                    Box::new(FakeDictionary {
+                        items: vec![(
+                            String::from("address"),
+                            Box::new(String::from("aa:bb:cc:dd:ee:ff")),
+                        )],
+                    }),
+                ),
+                (String::from("bytes"), Box::new(vec![1 as u8, 2, 3])),
+                (
+                    String::from("nested"),
+                    Box::new(vec![
+                        vec![
+                            String::from("string a"),
+                            String::from("string b"),
+                            String::from("string c"),
+                        ],
+                        vec![String::from("string 1"), String::from("string 2")],
+                    ]),
+                ),
+                (
+                    String::from("recursive"),
+                    Box::new(vec![FakeDictionary {
+                        items: vec![
+                            (String::from("name"), Box::new(String::from("bar"))),
+                            (String::from("number"), Box::new(200)),
+                            (
+                                String::from("other_struct"),
+                                Box::new(FakeDictionary {
+                                    items: vec![(
+                                        String::from("address"),
+                                        Box::new(String::from("xx")),
+                                    )],
+                                }),
+                            ),
+                            (String::from("bytes"), Box::new(Vec::<u8>::new())),
+                            (String::from("nested"), Box::new(Vec::<Vec<u8>>::new())),
+                            (String::from("recursive"), Box::new(Vec::<FakeDictionary>::new())),
+                        ],
+                    }]),
+                ),
+            ],
+        };
+        let result = <dbus::arg::PropMap as RefArgToRust>::ref_arg_to_rust(
+            &data_dbus,
+            String::from("Some Variable"),
+        );
+        assert!(result.is_ok());
+        let result = result.unwrap();
+        let result_struct = <SomeStruct as DBusArg>::from_dbus(result, None, None, None).unwrap();
+        let expected_struct = SomeStruct {
+            name: String::from("foo"),
+            number: 100,
+            other_struct: OtherStruct { address: String::from("aa:bb:cc:dd:ee:ff") },
+            bytes: vec![1, 2, 3],
+            nested: vec![
+                vec![String::from("string a"), String::from("string b"), String::from("string c")],
+                vec![String::from("string 1"), String::from("string 2")],
+            ],
+            recursive: vec![SomeStruct {
+                name: String::from("bar"),
+                number: 200,
+                other_struct: OtherStruct { address: String::from("xx") },
+                bytes: vec![],
+                nested: vec![],
+                recursive: vec![],
+            }],
+        };
+        assert_eq!(expected_struct, result_struct);
+    }
+}
diff --git a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs
index b06b52adfcac3381d3051485067928f7f0488865..9ff9cea800c4c4292ebb4dee6ea4cbeaafada633 100644
--- a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs
+++ b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs
@@ -1,5 +1,4 @@
 use dbus::arg::RefArg;
-use dbus::nonblock::SyncConnection;
 use dbus::strings::Path;
 use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};
 use dbus_projection::DisconnectWatcher;
diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs
index abb39e838958b022fe74b722f2c8dd870635743e..57464912e87be27e59039517058c828443035fe7 100644
--- a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs
+++ b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs
@@ -3,7 +3,6 @@ use btstack::bluetooth_media::{IBluetoothMedia, IBluetoothMediaCallback};
 use btstack::RPCProxy;
 
 use dbus::arg::RefArg;
-use dbus::nonblock::SyncConnection;
 use dbus::strings::Path;
 
 use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};