diff --git a/README-pwpolicy.md b/README-pwpolicy.md
index 7fd051643b6514be4ae07fa7d3c72e7160f9bb5f..8d158459eb2ba10f273b23bbe34b5a411c8aadaa 100644
--- a/README-pwpolicy.md
+++ b/README-pwpolicy.md
@@ -128,20 +128,20 @@ Variable | Description | Required
 `ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
 `ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
 `name` \| `cn` | The list of pwpolicy name strings. If name is not given, `global_policy` will be used automatically. | no
-`maxlife` \| `krbmaxpwdlife` | Maximum password lifetime in days. (int) | no
-`minlife` \| `krbminpwdlife` | Minimum password lifetime in hours. (int) | no
-`history` \| `krbpwdhistorylength` | Password history size. (int) | no
-`minclasses` \| `krbpwdmindiffchars` | Minimum number of character classes. (int) | no
-`minlength` \| `krbpwdminlength` | Minimum length of password. (int) | no
-`priority` \| `cospriority` | Priority of the policy, higher number means lower priority. (int) | no
-`maxfail` \| `krbpwdmaxfailure` | Consecutive failures before lockout. (int) | no
-`failinterval` \| `krbpwdfailurecountinterval` | Period after which failure count will be reset in seconds. (int) | no
-`lockouttime` \| `krbpwdlockoutduration` | Period for which lockout is enforced in seconds. (int) | no
-`maxrepeat` \| `ipapwdmaxrepeat` | Maximum number of same consecutive characters. Requires IPA 4.9+ (int) | no
-`maxsequence` \| `ipapwdmaxsequence` |  The maximum length of monotonic character sequences (abcd). Requires IPA 4.9+ (int) | no
-`dictcheck` \| `ipapwdictcheck` | Check if the password is a dictionary word. Requires IPA 4.9+ (int) | no
-`usercheck` \| `ipapwdusercheck` | Check if the password contains the username. Requires IPA 4.9+ (int) | no
-`gracelimit` \| `passwordgracelimit` |  Number of LDAP authentications allowed after expiration. Requires IPA 4.9.10 (int) | no
+`maxlife` \| `krbmaxpwdlife` | Maximum password lifetime in days. (int or "") | no
+`minlife` \| `krbminpwdlife` | Minimum password lifetime in hours. (int or "") | no
+`history` \| `krbpwdhistorylength` | Password history size. (int or "") | no
+`minclasses` \| `krbpwdmindiffchars` | Minimum number of character classes. (int or "") | no
+`minlength` \| `krbpwdminlength` | Minimum length of password. (int or "") | no
+`priority` \| `cospriority` | Priority of the policy, higher number means lower priority. (int or "") | no
+`maxfail` \| `krbpwdmaxfailure` | Consecutive failures before lockout. (int or "") | no
+`failinterval` \| `krbpwdfailurecountinterval` | Period after which failure count will be reset in seconds. (int or "") | no
+`lockouttime` \| `krbpwdlockoutduration` | Period for which lockout is enforced in seconds. (int or "") | no
+`maxrepeat` \| `ipapwdmaxrepeat` | Maximum number of same consecutive characters. Requires IPA 4.9+ (int or "") | no
+`maxsequence` \| `ipapwdmaxsequence` |  The maximum length of monotonic character sequences (abcd). Requires IPA 4.9+ (int or "") | no
+`dictcheck` \| `ipapwdictcheck` | Check if the password is a dictionary word. Requires IPA 4.9+. (bool or "") | no
+`usercheck` \| `ipapwdusercheck` | Check if the password contains the username. Requires IPA 4.9+. (bool or "") | no
+`gracelimit` \| `passwordgracelimit` |  Number of LDAP authentications allowed after expiration. Requires IPA 4.9.10 (int or "") | no
 `state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
 
 
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
index 6bae7cc3bf923ab3e5808a66e9f207d571e994f5..0af0d63e3ae4b93062ca0663902f8251f03b2331 100644
--- a/plugins/module_utils/ansible_freeipa_module.py
+++ b/plugins/module_utils/ansible_freeipa_module.py
@@ -30,7 +30,7 @@ __all__ = ["gssapi", "netaddr", "api", "ipalib_errors", "Env",
            "kinit_password", "kinit_keytab", "run", "DN", "VERSION",
            "paths", "tasks", "get_credentials_if_valid", "Encoding",
            "DNSName", "getargspec", "certificate_loader",
-           "write_certificate_list"]
+           "write_certificate_list", "boolean"]
 
 import os
 # ansible-freeipa requires locale to be C, IPA requires utf-8.
@@ -49,6 +49,7 @@ from ansible.module_utils._text import to_text
 from ansible.module_utils.common.text.converters import jsonify
 from ansible.module_utils import six
 from ansible.module_utils.common._collections_compat import Mapping
+from ansible.module_utils.parsing.convert_bool import boolean
 
 # Import getargspec from inspect or provide own getargspec for
 # Python 2 compatibility with Python 3.11+.
diff --git a/plugins/modules/ipapwpolicy.py b/plugins/modules/ipapwpolicy.py
index f75635536c27357fdf247956dee7767867d4a5a8..a71a88dd20fb1824cc16ab10c5d6ea7c968f4695 100644
--- a/plugins/modules/ipapwpolicy.py
+++ b/plugins/modules/ipapwpolicy.py
@@ -45,82 +45,84 @@ options:
     required: false
     aliases: ["cn"]
   maxlife:
-    description: Maximum password lifetime (in days)
+    description: Maximum password lifetime (in days). (int or "")
     type: str
     required: false
     aliases: ["krbmaxpwdlife"]
   minlife:
-    description: Minimum password lifetime (in hours)
+    description: Minimum password lifetime (in hours). (int or "")
     type: str
     required: false
     aliases: ["krbminpwdlife"]
   history:
-    description: Password history size
+    description: Password history size. (int or "")
     type: str
     required: false
     aliases: ["krbpwdhistorylength"]
   minclasses:
-    description: Minimum number of character classes
+    description: Minimum number of character classes. (int or "")
     type: str
     required: false
     aliases: ["krbpwdmindiffchars"]
   minlength:
-    description: Minimum length of password
+    description: Minimum length of password. (int or "")
     type: str
     required: false
     aliases: ["krbpwdminlength"]
   priority:
-    description: Priority of the policy (higher number means lower priority)
+    description: >
+      Priority of the policy (higher number means lower priority). (int or "")
     type: str
     required: false
     aliases: ["cospriority"]
   maxfail:
-    description: Consecutive failures before lockout
+    description: Consecutive failures before lockout. (int or "")
     type: str
     required: false
     aliases: ["krbpwdmaxfailure"]
   failinterval:
-    description: Period after which failure count will be reset (seconds)
+    description: >
+      Period after which failure count will be reset (seconds). (int or "")
     type: str
     required: false
     aliases: ["krbpwdfailurecountinterval"]
   lockouttime:
-    description: Period for which lockout is enforced (seconds)
+    description: Period for which lockout is enforced (seconds). (int or "")
     type: str
     required: false
     aliases: ["krbpwdlockoutduration"]
   maxrepeat:
     description: >
       Maximum number of same consecutive characters.
-      Requires IPA 4.9+
+      Requires IPA 4.9+. (int or "")
     type: str
     required: false
     aliases: ["ipapwdmaxrepeat"]
   maxsequence:
     description: >
       The maximum length of monotonic character sequences (abcd).
-      Requires IPA 4.9+
+      Requires IPA 4.9+. (int or "")
     type: str
     required: false
     aliases: ["ipapwdmaxsequence"]
   dictcheck:
     description: >
       Check if the password is a dictionary word.
-      Requires IPA 4.9+
+      Requires IPA 4.9+. (bool or "")
     type: str
     required: false
     aliases: ["ipapwdictcheck"]
   usercheck:
     description: >
       Check if the password contains the username.
-      Requires IPA 4.9+
+      Requires IPA 4.9+. (bool or "")
     type: str
     required: false
     aliases: ["ipapwdusercheck"]
   gracelimit:
     description: >
       Number of LDAP authentications allowed after expiration.
-      Requires IPA 4.10.1+
+      Requires IPA 4.10.1+. (int or "")
     type: str
     required: false
     aliases: ["passwordgracelimit"]
@@ -151,7 +153,7 @@ RETURN = """
 """
 
 from ansible.module_utils.ansible_freeipa_module import \
-    IPAAnsibleModule, compare_args_ipa
+    IPAAnsibleModule, compare_args_ipa, boolean
 
 
 def find_pwpolicy(module, name):
@@ -359,17 +361,12 @@ def main():
     gracelimit = int_or_empty_param(gracelimit, "gracelimit")
 
     def bool_or_empty_param(value, param):  # pylint: disable=R1710
-        # As of Ansible 2.14, values True, False, Yes an No, with variable
-        # capitalization are accepted by Ansible.
-        if not value:
+        if value is None or value == "":
             return value
-        if value in ["TRUE", "True", "true", "YES", "Yes", "yes"]:
-            return True
-        if value in ["FALSE", "False", "false", "NO", "No", "no"]:
-            return False
-        ansible_module.fail_json(
-            msg="Invalid value '%s' for argument '%s'." % (value, param)
-        )
+        try:
+            return boolean(value)
+        except TypeError as terr:
+            ansible_module.fail_json(msg="Param '%s': %s" % (param, str(terr)))
 
     dictcheck = bool_or_empty_param(dictcheck, "dictcheck")
     usercheck = bool_or_empty_param(usercheck, "usercheck")
diff --git a/tests/pwpolicy/test_pwpolicy_invalid_data_type.yml b/tests/pwpolicy/test_pwpolicy_invalid_data_type.yml
index 8a1aaed7220f0845163099c173febbe89261d063..4c97622b9497d036f6e4a19043b6702d1d6b051c 100644
--- a/tests/pwpolicy/test_pwpolicy_invalid_data_type.yml
+++ b/tests/pwpolicy/test_pwpolicy_invalid_data_type.yml
@@ -103,7 +103,7 @@
       name: ops
       dictcheck: "error"
     register: result
-    failed_when: result.changed or (result.failed and "Invalid value 'error' for argument 'dictcheck" not in result.msg)
+    failed_when: result.changed or (result.failed and "is not a valid boolean" not in result.msg)
     when: ipa_version is version("4.9", ">=")
 
   - name: Ensure invalid values for usercheck raise proper error.
@@ -113,7 +113,7 @@
       name: ops
       usercheck: "error"
     register: result
-    failed_when: result.changed or (result.failed and "Invalid value 'error' for argument 'usercheck'" not in result.msg)
+    failed_when: result.changed or (result.failed and "is not a valid boolean" not in result.msg)
     when: ipa_version is version("4.9", ">=")
 
   - name: Ensure invalid values for gracelimit raise proper error.