diff --git a/README-automountmap.md b/README-automountmap.md
index 208dd53deb5e6b7ddba8a42d85204577889c7ce9..77e6af092038fee06e214e67a9a1816887a50eca 100644
--- a/README-automountmap.md
+++ b/README-automountmap.md
@@ -54,6 +54,21 @@ Example playbook to ensure presence of an automount map:
       desc: "this is a map for servers in the DMZ"
 ```
 
+Automount maps can contain a submount key, which defines a mount location within the map the references another map. On FreeIPA, this is known as an indirect map. An indirect automount map is equivalent to adding a proper automount key to a map, referencyng another map (this second map is the indirect map). Use `parent` and `mount` parameters to create an indirect automount map with ansible-freeipa, without the need to directly manage the automount keys.
+
+Example playbook to ensure an indirect automount map is present:
+
+```yaml
+---
+- name: Playbook to add an indirect automount map
+  ipaautomountmap:
+    ipaadmin_password: SomeADMINpassword
+    name: auto.indirect
+    location: DMZ
+    parent: auto.DMZ
+    mount: dmz_indirect
+```
+
 Example playbook to ensure auto.DMZi is absent:
 
 ```yaml
@@ -81,16 +96,14 @@ Variable | Description | Required
 `ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
 `name` \| `mapname` \| `map` \| `automountmapname` | Name of the map to manage | yes
 `location` \| `automountlocation` \| `automountlocationcn` | Location name. | yes
+`parentmap` | Parent map of the indirect map. Can only be used when creating new maps. Default: auto.master | no
+`mount` | Indirect map mount point, relative to parent map. | yes, if `parent` is used.
 `desc` \| `description` | Description of the map | yes
 `state` | The state to ensure. It can be one of `present`, or `absent`, default: `present`. | no
 
 
-Notes
-=====
-
-Creation of indirect mount points are not supported.
-
 Authors
 =======
 
-Chris Procter
+- Chris Procter
+- Rafael Jeffman
diff --git a/playbooks/automount/automount-map-indirect-map.yml b/playbooks/automount/automount-map-indirect-map.yml
new file mode 100644
index 0000000000000000000000000000000000000000..38359e553154e1a6272907f900db856702735764
--- /dev/null
+++ b/playbooks/automount/automount-map-indirect-map.yml
@@ -0,0 +1,14 @@
+---
+- name: Managed automount maps
+  hosts: ipaserver
+  become: false
+  gather_facts: false
+
+  tasks:
+  - name: Playbook to add an indirect automount map
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      name: auto.indirect
+      location: DMZ
+      parent: auto.DMZ
+      mount: dmz_indirect
diff --git a/plugins/modules/ipaautomountmap.py b/plugins/modules/ipaautomountmap.py
index 1590ebb69518366b476cc13599a04ccb8f475c19..668e887a313a5936101e787bf6fa1cff0e925d81 100644
--- a/plugins/modules/ipaautomountmap.py
+++ b/plugins/modules/ipaautomountmap.py
@@ -37,6 +37,7 @@ module: ipaautomountmap
 author:
   - Chris Procter (@chr15p)
   - Thomas Woerner (@t-woerner)
+  - Rafael Jeffman (@rjeffman)
 short_description: Manage FreeIPA autommount map
 description:
 - Add, delete, and modify an IPA automount map
@@ -59,6 +60,16 @@ options:
     type: str
     aliases: ["description"]
     required: false
+  parentmap:
+    description: |
+      Parent map of the indirect map. Can only be used when creating
+      new maps.
+    type: str
+    required: false
+  mount:
+    description: Indirect map mount point, relative to parent map.
+    type: str
+    required: false
   state:
     description: State to ensure
     type: str
@@ -75,6 +86,14 @@ EXAMPLES = '''
       location: DMZ
       desc: "this is a map for servers in the DMZ"
 
+  - name: ensure indirect map exists
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      name: auto.INDIRECT
+      location: DMZ
+      parentmap: auto.DMZ
+      mount: indirect
+
   - name: remove a map named auto.DMZ in location DMZ if it exists
     ipaautomountmap:
       ipaadmin_password: SomeADMINpassword
@@ -110,6 +129,35 @@ class AutomountMap(IPAAnsibleModule):
         else:
             return response["result"]
 
+    def get_indirect_map_keys(self, location, name):
+        """Check if 'name' is an indirect map for 'parentmap'."""
+        try:
+            maps = self.ipa_command("automountmap_find", location, {})
+        except Exception:  # pylint: disable=broad-except
+            return []
+
+        result = []
+        for check_map in maps.get("result", []):
+            _mapname = check_map['automountmapname'][0]
+            keys = self.ipa_command(
+                "automountkey_find",
+                location,
+                {
+                    "automountmapautomountmapname": _mapname,
+                    "all": True
+                }
+            )
+            cmp_value = (
+                name if _mapname == "auto.master" else "ldap:{0}".format(name)
+            )
+            result.extend([
+                (location, _mapname, key.get("automountkey")[0])
+                for key in keys.get("result", [])
+                for mount_info in key.get("automountinformation", [])
+                if cmp_value in mount_info
+            ])
+        return result
+
     def check_ipa_params(self):
         invalid = []
         name = self.params_get("name")
@@ -118,15 +166,27 @@ class AutomountMap(IPAAnsibleModule):
             if len(name) != 1:
                 self.fail_json(msg="Exactly one name must be provided for"
                                    " 'state: present'.")
+            mount = self.params_get("mount") or False
+            parentmap = self.params_get("parentmap")
+            if parentmap:
+                if not mount:
+                    self.fail_json(
+                        msg="Must provide 'mount' parameter for indirect map."
+                    )
+                elif parentmap != "auto.master" and mount[0] == "/":
+                    self.fail_json(
+                        msg="mount point is relative to parent map, "
+                            "cannot begin with '/'"
+                    )
         if state == "absent":
             if len(name) == 0:
                 self.fail_json(msg="At least one 'name' must be provided for"
                                    " 'state: absent'")
-            invalid = ["desc"]
+            invalid = ["desc", "parentmap", "mount"]
 
         self.params_fail_used_invalid(invalid, state)
 
-    def get_args(self, mapname, desc):
+    def get_args(self, mapname, desc, parentmap, mount):
         # automountmapname is required for all automountmap operations.
         if not mapname:
             self.fail_json(msg="automountmapname cannot be None or empty.")
@@ -134,6 +194,11 @@ class AutomountMap(IPAAnsibleModule):
         # An empty string is valid and will clear the attribute.
         if desc is not None:
             _args["description"] = desc
+        # indirect map attributes
+        if parentmap is not None:
+            _args["parentmap"] = parentmap
+        if mount is not None:
+            _args["key"] = mount
         return _args
 
     def define_ipa_commands(self):
@@ -141,28 +206,102 @@ class AutomountMap(IPAAnsibleModule):
         state = self.params_get("state")
         location = self.params_get("location")
         desc = self.params_get("desc")
+        mount = self.params_get("mount")
+        parentmap = self.params_get("parentmap")
 
         for mapname in name:
             automountmap = self.get_automountmap(location, mapname)
 
+            is_indirect_map = any([parentmap, mount])
+
             if state == "present":
-                args = self.get_args(mapname, desc)
+                args = self.get_args(mapname, desc, parentmap, mount)
                 if automountmap is None:
-                    self.commands.append([location, "automountmap_add", args])
+                    if is_indirect_map:
+                        if (
+                            parentmap and
+                            self.get_automountmap(location, parentmap) is None
+                        ):
+                            self.fail_json(msg="Parent map does not exist.")
+                        self.commands.append(
+                            [location, "automountmap_add_indirect", args]
+                        )
+                    else:
+                        self.commands.append(
+                            [location, "automountmap_add", args]
+                        )
                 else:
-                    if not compare_args_ipa(self, args, automountmap):
+                    has_changes = not compare_args_ipa(
+                        self, args, automountmap, ['parentmap', 'key']
+                    )
+                    if is_indirect_map:
+                        map_config = (
+                            location, parentmap or "auto.master", mount
+                        )
+                        indirects = self.get_indirect_map_keys(
+                            location, mapname
+                        )
+                        if map_config not in indirects or has_changes:
+                            self.fail_json(
+                                msg="Indirect maps can only be created, "
+                                    "not modified."
+                            )
+                    elif has_changes:
                         self.commands.append(
                             [location, "automountmap_mod", args]
                         )
 
-            if state == "absent":
+            elif state == "absent":
+                def find_keys(parent_loc, parent_map, parent_key):
+                    return self.ipa_command(
+                        "automountkey_show",
+                        parent_loc,
+                        {
+                            "automountmapautomountmapname": parent_map,
+                            "automountkey": parent_key,
+                        }
+                    ).get("result")
+
                 if automountmap is not None:
+                    indirects = self.get_indirect_map_keys(location, mapname)
+                    # Remove indirect map configurations for this map
+                    self.commands.extend([
+                        (
+                            ploc,
+                            "automountkey_del",
+                            {
+                                "automountmapautomountmapname": pmap,
+                                "automountkey": pkey,
+                            }
+                        )
+                        for ploc, pmap, pkey in indirects
+                        if find_keys(ploc, pmap, pkey)
+                    ])
+                    # Remove map
                     self.commands.append([
                         location,
                         "automountmap_del",
                         {"automountmapname": [mapname]}
                     ])
 
+            # ensure commands are unique and automountkey commands are
+            # executed first in the list
+            def hashable_dict(dictionaire):
+                return tuple(
+                    (k, tuple(v) if isinstance(v, (list, tuple)) else v)
+                    for k, v in dictionaire.items()
+                )
+
+            cmds = [
+                (name, cmd, hashable_dict(args))
+                for name, cmd, args in self.commands
+            ]
+            self.commands = [
+                (name, cmd, dict(args))
+                for name, cmd, args in
+                sorted(set(cmds), key=lambda cmd: cmd[1])
+            ]
+
 
 def main():
     ipa_module = AutomountMap(
@@ -184,6 +323,10 @@ def main():
                       required=False,
                       default=None
                       ),
+            parentmap=dict(
+                type="str", required=False, default=None
+            ),
+            mount=dict(type="str", required=False, default=None),
         ),
     )
     changed = False
diff --git a/tests/automount/test_automountmap_indirect.yml b/tests/automount/test_automountmap_indirect.yml
new file mode 100644
index 0000000000000000000000000000000000000000..200fe1ef4784057747e0879e04226c2dd908c3c6
--- /dev/null
+++ b/tests/automount/test_automountmap_indirect.yml
@@ -0,0 +1,143 @@
+---
+- name: Test automountmap
+  hosts: "{{ ipa_test_host | default('ipaserver') }}"
+  become: no
+  gather_facts: no
+
+  tasks:
+  # setup environment
+  - name: Ensure test maps are absent
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name:
+        - DirectMap
+        - IndirectMap
+        - IndirectMapDefault
+        - IndirectMapDefaultAbsolute
+      state: absent
+
+  - name: Ensure test location is present
+    ipaautomountlocation:
+      ipaadmin_password: SomeADMINpassword
+      name: TestIndirect
+
+  - name: Ensure parent map is present
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: DirectMap
+
+  # TESTS
+  - name: Mount point cannot start with '/' if parentmap is not 'auto.master'
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      parentmap: DirectMap
+      mount: '/absolute/path/will/fail'
+    register: result
+    failed_when: not result.failed or 'mount point is relative to parent map' not in result.msg
+
+  - name: Ensure indirect map is present
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      parentmap: DirectMap
+      mount: indirect
+    register: result
+    failed_when: result.failed or not result.changed
+
+  - name: Ensure indirect map is present, again
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      parentmap: DirectMap
+      mount: indirect
+    register: result
+    failed_when: result.failed or result.changed
+
+  - name: Ensure indirect map is absent
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      state: absent
+    register: result
+    failed_when: result.failed or not result.changed
+
+  - name: Ensure indirect map is absent, again
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      state: absent
+    register: result
+    failed_when: result.failed or result.changed
+
+  - name: Ensure indirect map is present, after being deleted
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      parentmap: DirectMap
+      mount: indirect
+    register: result
+    failed_when: result.failed or not result.changed
+
+  - name: Ensure indirect map is present, after being deleted, again
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMap
+      parentmap: DirectMap
+      mount: indirect
+    register: result
+    failed_when: result.failed or result.changed
+
+  - name: Ensure indirect map is present with default parent (auto.master)
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMapDefault
+      mount: indirect_with_default
+    register: result
+    failed_when: result.failed or not result.changed
+
+  - name: Ensure indirect map is present with default parent (auto.master), again
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMapDefault
+      mount: indirect_with_default
+    register: result
+    failed_when: result.failed or result.changed
+
+  - name: Absolute paths must workd with 'auto.master'
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name: IndirectMapDefaultAbsolute
+      mount: /valid/path/indirect_with_default
+    register: result
+    failed_when: result.failed or not result.changed
+
+  # Cleanup
+  - name: Ensure test maps are absent
+    ipaautomountmap:
+      ipaadmin_password: SomeADMINpassword
+      location: TestIndirect
+      name:
+        - DirectMap
+        - IndirectMap
+        - IndirectMapDefault
+        - IndirectMapDefaultAbsolute
+      state: absent
+
+  - name: Ensure test location is absent
+    ipaautomountlocation:
+      ipaadmin_password: SomeADMINpassword
+      name: TestIndirect
+      state: absent