diff --git a/projects/aca-folder-rules/src/lib/mock/actions.mock.ts b/projects/aca-folder-rules/src/lib/mock/actions.mock.ts
index 88a992c9d..cbd3e7fc5 100644
--- a/projects/aca-folder-rules/src/lib/mock/actions.mock.ts
+++ b/projects/aca-folder-rules/src/lib/mock/actions.mock.ts
@@ -24,7 +24,7 @@
  */
 
 import { ActionDefinitionList } from '@alfresco/js-api';
-import { ActionDefinitionTransformed, ActionParameterDefinitionTransformed } from '../model/rule-action.model';
+import { ActionDefinitionTransformed, ActionParameterDefinitionTransformed, RuleAction } from '../model/rule-action.model';
 
 export const actionDefListMock: ActionDefinitionList = {
   list: {
@@ -43,7 +43,7 @@ export const actionDefListMock: ActionDefinitionList = {
             name: 'mock-action-parameter-text',
             type: 'd:text',
             multiValued: false,
-            mandatory: false,
+            mandatory: true,
             displayLabel: 'Mock action parameter text'
           },
           {
@@ -73,7 +73,7 @@ const actionParam1TransformedMock: ActionParameterDefinitionTransformed = {
   name: 'mock-action-parameter-text',
   type: 'd:text',
   multiValued: false,
-  mandatory: false,
+  mandatory: true,
   displayLabel: 'Mock action parameter text'
 };
 
@@ -106,3 +106,31 @@ const action2TransformedMock: ActionDefinitionTransformed = {
 };
 
 export const actionsTransformedListMock: ActionDefinitionTransformed[] = [action1TransformedMock, action2TransformedMock];
+
+export const validActionMock: RuleAction = {
+  actionDefinitionId: 'mock-action-1-definition',
+  params: {
+    'mock-action-parameter-text': 'mock'
+  }
+};
+export const nonExistentActionDefinitionIdMock: RuleAction = {
+  actionDefinitionId: 'non-existent-action-definition-id',
+  params: {}
+};
+export const missingMandatoryParameterMock: RuleAction = {
+  actionDefinitionId: 'mock-action-1-definition',
+  params: {}
+};
+export const incompleteMandatoryParameterMock: RuleAction = {
+  actionDefinitionId: 'mock-action-1-definition',
+  params: {
+    'mock-action-parameter-text': ''
+  }
+};
+export const validActionsMock: RuleAction[] = [
+  validActionMock,
+  {
+    actionDefinitionId: 'mock-action-2-definition',
+    params: {}
+  }
+];
diff --git a/projects/aca-folder-rules/src/lib/model/rule-action.model.ts b/projects/aca-folder-rules/src/lib/model/rule-action.model.ts
index 8fbeacaa9..1d68c4802 100644
--- a/projects/aca-folder-rules/src/lib/model/rule-action.model.ts
+++ b/projects/aca-folder-rules/src/lib/model/rule-action.model.ts
@@ -28,6 +28,11 @@ export interface RuleAction {
   params: { [key: string]: unknown };
 }
 
+export const isRuleAction = (obj): obj is RuleAction =>
+  typeof obj === 'object' && typeof obj.actionDefinitionId === 'string' && typeof obj.params === 'object';
+export const isRuleActions = (obj): obj is RuleAction[] =>
+  typeof obj === 'object' && obj instanceof Array && obj.reduce((acc, curr) => acc && isRuleAction(curr), true);
+
 export interface ActionDefinitionTransformed {
   id: string;
   name: string;
diff --git a/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action-list.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action-list.ui-component.ts
index 129a03035..964fcc069 100644
--- a/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action-list.ui-component.ts
+++ b/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action-list.ui-component.ts
@@ -1,7 +1,33 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 Alfresco Software Limited
+ *
+ * This file is part of the Alfresco Example Content Application.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail.  Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * The Alfresco Example Content Application is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Alfresco Example Content Application is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
+ */
+
 import { Component, forwardRef, Input, OnDestroy, ViewEncapsulation } from '@angular/core';
-import { ControlValueAccessor, FormArray, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { ControlValueAccessor, FormArray, FormControl, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 import { ActionDefinitionTransformed, RuleAction } from '../../model/rule-action.model';
 import { Subscription } from 'rxjs';
+import { ruleActionValidator } from '../validators/rule-actions.validator';
 
 @Component({
   selector: 'aca-rule-action-list',
@@ -63,7 +89,7 @@ export class RuleActionListUiComponent implements ControlValueAccessor, OnDestro
       actionDefinitionId: null,
       params: {}
     };
-    this.formArray.push(new FormControl(newAction));
+    this.formArray.push(new FormControl(newAction, [Validators.required, ruleActionValidator(this.actionDefinitions)]));
   }
 
   ngOnDestroy() {
diff --git a/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action.ui-component.ts
index cfea506dc..52dd22e97 100644
--- a/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action.ui-component.ts
+++ b/projects/aca-folder-rules/src/lib/rule-details/actions/rule-action.ui-component.ts
@@ -1,9 +1,36 @@
-import { Component, forwardRef, Input, OnDestroy, ViewEncapsulation } from '@angular/core';
-import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 Alfresco Software Limited
+ *
+ * This file is part of the Alfresco Example Content Application.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail.  Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * The Alfresco Example Content Application is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Alfresco Example Content Application is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { Component, forwardRef, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
+import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 import { ActionDefinitionTransformed, RuleAction } from '../../model/rule-action.model';
 import { CardViewItem } from '@alfresco/adf-core/lib/card-view/interfaces/card-view-item.interface';
 import { CardViewBoolItemModel, CardViewTextItemModel, CardViewUpdateService, UpdateNotification } from '@alfresco/adf-core';
 import { ActionParameterDefinition } from '@alfresco/js-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
 
 @Component({
   selector: 'aca-rule-action',
@@ -20,7 +47,7 @@ import { ActionParameterDefinition } from '@alfresco/js-api';
     CardViewUpdateService
   ]
 })
-export class RuleActionUiComponent implements ControlValueAccessor, OnDestroy {
+export class RuleActionUiComponent implements ControlValueAccessor, OnInit, OnDestroy {
   private _actionDefinitions: ActionDefinitionTransformed[];
   @Input()
   get actionDefinitions(): ActionDefinitionTransformed[] {
@@ -40,12 +67,12 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnDestroy {
   }
 
   form = new FormGroup({
-    actionDefinitionId: new FormControl('copy')
+    actionDefinitionId: new FormControl('', Validators.required)
   });
 
   cardViewItems: CardViewItem[] = [];
-
   parameters: { [key: string]: unknown } = {};
+  private onDestroy$ = new Subject<boolean>();
 
   get selectedActionDefinitionId(): string {
     return this.form.get('actionDefinitionId').value;
@@ -55,28 +82,6 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnDestroy {
     return this.actionDefinitions.find((actionDefinition: ActionDefinitionTransformed) => actionDefinition.id === this.selectedActionDefinitionId);
   }
 
-  private formSubscription = this.form.valueChanges.subscribe(() => {
-    this.setDefaultParameters();
-    this.setCardViewProperties();
-    this.onChange({
-      actionDefinitionId: this.selectedActionDefinitionId,
-      params: this.parameters
-    });
-    this.onTouch();
-  });
-
-  private updateServiceSubscription = this.cardViewUpdateService.itemUpdated$.subscribe((updateNotification: UpdateNotification) => {
-    this.parameters = {
-      ...this.parameters,
-      ...updateNotification.changed
-    };
-    this.onChange({
-      actionDefinitionId: this.selectedActionDefinitionId,
-      params: this.parameters
-    });
-    this.onTouch();
-  });
-
   onChange: (action: RuleAction) => void = () => undefined;
   onTouch: () => void = () => undefined;
 
@@ -101,17 +106,51 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnDestroy {
     this.onTouch = fn;
   }
 
+  ngOnInit() {
+    this.form.valueChanges.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
+      this.setDefaultParameters();
+      this.setCardViewProperties();
+      this.onChange({
+        actionDefinitionId: this.selectedActionDefinitionId,
+        params: this.parameters
+      });
+      this.onTouch();
+    });
+
+    this.cardViewUpdateService.itemUpdated$.pipe(takeUntil(this.onDestroy$)).subscribe((updateNotification: UpdateNotification) => {
+      this.parameters = {
+        ...this.parameters,
+        ...updateNotification.changed
+      };
+      this.onChange({
+        actionDefinitionId: this.selectedActionDefinitionId,
+        params: this.parameters
+      });
+      this.onTouch();
+    });
+  }
+
   ngOnDestroy() {
-    this.formSubscription.unsubscribe();
-    this.updateServiceSubscription.unsubscribe();
+    this.onDestroy$.next();
+    this.onDestroy$.complete();
   }
 
   setCardViewProperties() {
     this.cardViewItems = (this.selectedActionDefinition?.parameterDefinitions ?? []).map((paramDef) => {
       const cardViewPropertiesModel = {
-        label: paramDef.displayLabel,
+        label: paramDef.displayLabel + (paramDef.mandatory ? ' *' : ''),
         key: paramDef.name,
-        editable: true
+        editable: true,
+        ...(paramDef.mandatory
+          ? {
+              validators: [
+                {
+                  message: 'ACA_FOLDER_RULES.RULE_DETAILS.ERROR.REQUIRED',
+                  isValid: (value: unknown) => !!value
+                }
+              ]
+            }
+          : {})
       };
       switch (paramDef.type) {
         case 'd:boolean':
diff --git a/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts
index f5508905f..b36262ffa 100644
--- a/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts
+++ b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts
@@ -31,6 +31,7 @@ import { Rule } from '../model/rule.model';
 import { ruleCompositeConditionValidator } from './validators/rule-composite-condition.validator';
 import { FolderRulesService } from '../services/folder-rules.service';
 import { ActionDefinitionTransformed } from '../model/rule-action.model';
+import { ruleActionsValidator } from './validators/rule-actions.validator';
 
 @Component({
   selector: 'aca-rule-details',
@@ -136,7 +137,7 @@ export class RuleDetailsUiComponent implements OnInit, OnDestroy {
       errorScript: new UntypedFormControl(this.value.errorScript),
       isInheritable: new UntypedFormControl(this.value.isInheritable),
       isEnabled: new UntypedFormControl(this.value.isEnabled),
-      actions: new UntypedFormControl(this.value.actions)
+      actions: new UntypedFormControl(this.value.actions, [Validators.required, ruleActionsValidator(this.actionDefinitions)])
     });
     this.readOnly = this._readOnly;
 
diff --git a/projects/aca-folder-rules/src/lib/rule-details/validators/rule-actions.validator.spec.ts b/projects/aca-folder-rules/src/lib/rule-details/validators/rule-actions.validator.spec.ts
new file mode 100644
index 000000000..f06895143
--- /dev/null
+++ b/projects/aca-folder-rules/src/lib/rule-details/validators/rule-actions.validator.spec.ts
@@ -0,0 +1,69 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 Alfresco Software Limited
+ *
+ * This file is part of the Alfresco Example Content Application.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail.  Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * The Alfresco Example Content Application is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Alfresco Example Content Application is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { FormControl, ValidatorFn } from '@angular/forms';
+import { ruleActionsValidator, ruleActionValidator } from './rule-actions.validator';
+import {
+  actionsTransformedListMock,
+  incompleteMandatoryParameterMock,
+  missingMandatoryParameterMock,
+  nonExistentActionDefinitionIdMock,
+  validActionMock,
+  validActionsMock
+} from '../../mock/actions.mock';
+
+describe('ruleActionsValidator', () => {
+  let validatorFn: ValidatorFn;
+
+  beforeEach(() => {
+    validatorFn = ruleActionValidator(actionsTransformedListMock);
+  });
+
+  it('should return null for a valid action', () => {
+    const control = new FormControl(validActionMock);
+    expect(validatorFn(control)).toBeNull();
+  });
+
+  it('should return a validation error for an non-existent action definition ID', () => {
+    const control = new FormControl(nonExistentActionDefinitionIdMock);
+    expect(validatorFn(control)).toEqual({ ruleActionInvalid: true });
+  });
+
+  it('should return a validation error for an missing mandatory parameter', () => {
+    const control = new FormControl(missingMandatoryParameterMock);
+    expect(validatorFn(control)).toEqual({ ruleActionInvalid: true });
+  });
+
+  it('should return a validation error for an incomplete mandatory parameter', () => {
+    const control = new FormControl(incompleteMandatoryParameterMock);
+    expect(validatorFn(control)).toEqual({ ruleActionInvalid: true });
+  });
+
+  it('should return null for valid actions', () => {
+    const multipleActionsValidatorFn = ruleActionsValidator(actionsTransformedListMock);
+    const control = new FormControl(validActionsMock);
+    expect(multipleActionsValidatorFn(control)).toBeNull();
+  });
+});
diff --git a/projects/aca-folder-rules/src/lib/rule-details/validators/rule-actions.validator.ts b/projects/aca-folder-rules/src/lib/rule-details/validators/rule-actions.validator.ts
new file mode 100644
index 000000000..70dc288b0
--- /dev/null
+++ b/projects/aca-folder-rules/src/lib/rule-details/validators/rule-actions.validator.ts
@@ -0,0 +1,61 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 Alfresco Software Limited
+ *
+ * This file is part of the Alfresco Example Content Application.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail.  Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * The Alfresco Example Content Application is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Alfresco Example Content Application is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
+import {
+  ActionDefinitionTransformed,
+  ActionParameterDefinitionTransformed,
+  isRuleAction,
+  isRuleActions,
+  RuleAction
+} from '../../model/rule-action.model';
+
+const isRuleActionValid = (value: unknown, actionDefinitions: ActionDefinitionTransformed[]): boolean => {
+  const actionDefinition = isRuleAction(value)
+    ? actionDefinitions.find((actionDef: ActionDefinitionTransformed) => value.actionDefinitionId === actionDef.id)
+    : undefined;
+  return (
+    isRuleAction(value) &&
+    actionDefinition &&
+    actionDefinition.parameterDefinitions.reduce(
+      (isValid: boolean, paramDef: ActionParameterDefinitionTransformed) => isValid && (!paramDef.mandatory || !!value.params[paramDef.name]),
+      true
+    )
+  );
+};
+
+const isRuleActionsValid = (value: unknown, actionDefinitions: ActionDefinitionTransformed[]): boolean =>
+  isRuleActions(value) &&
+  value.reduce((isValid: boolean, currentAction: RuleAction) => isValid && isRuleActionValid(currentAction, actionDefinitions), true);
+
+export const ruleActionValidator =
+  (actionDefinitions: ActionDefinitionTransformed[]): ValidatorFn =>
+  (control: AbstractControl): ValidationErrors | null =>
+    isRuleActionValid(control.value, actionDefinitions) ? null : { ruleActionInvalid: true };
+
+export const ruleActionsValidator =
+  (actionDefinitions: ActionDefinitionTransformed[]): ValidatorFn =>
+  (control: AbstractControl): ValidationErrors | null =>
+    isRuleActionsValid(control.value, actionDefinitions) ? null : { ruleActionsInvalid: true };