Yes, use hook_entity_bundle_field_info_alter
and when you add a constraint to the field (and not to a item or property), your constraint gets the entire field item list, so you can check how many items you have of which type, see FieldConfigInterface::addConstraint:
function mymodule_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
if ($entity_type->id() == 'node' && $bundle == 'page') {
$fields['field_paragraph']->addConstraint('MymoduleParagraphTypes');
}
}
Example for a constraint restricting the field to four paragraph items of a specific type:
public function validate($items, Constraint $constraint) {
$paragraphs = array_filter($items->referencedEntities(), function ($paragraph) {
return $paragraph->bundle() === 'image';
});
if (!empty($paragraphs) && count($paragraphs) != 4) {
$this->context->addViolation($constraint->errorMessage);
}
}
You can generate the constraint with the Drush command:
drush generate plugin-constraint
Edit:
If you need to check field values inside of the paragraphs then use $item->entity. See How to validate a paragraph field?